By Titus Pullo


2018-01-16 17:44:02 8 Comments

I have a python script that I run on AWS. The script contains the lambda_handler(event, context) function that is called by AWS. Now, I'd like to create a new lambda function that acts as unit test. A typical unit test schema is defined as:

import unittest

def my_function(a):
    return a + 1

class Test(unittest.TestCase):

    def test_correct(self):
        self.assertEqual( my_function(1), 2)

if __name__ == '__main__':
    unittest.main()

In AWS, the lambda_handler(event, context) function is called. How can I make the unittest_lambda_handler(event, context) to perform the unit test?

So I am guessing my code (in the unit test script) should look like:

import main_lambda_function
import unittest

    def unittest_lambda_handler(event, context):
         #what should this function do?

    class MyTest(unittest.TestCase):
         def return_type(self,event, context):
            self.assertTrue(isinstance(main_lambda_function.lambda_handler(event, context),int))

Is this the correct approach?If so, what should unittest_lambda_handler do?

5 comments

@Wheat 2018-12-05 11:07:40

Calling lambda_handler(event, context) is an integration test. This function is intended to execute the complete workflow of your Lambda script.

You should separate the functions you want to unit test out of the lambda_handler() function:

def my_function(a):
    return a + 1

def lambda_handler(event, context):
    return my_function(event)

Now you can test my_function as a normal unit test.

If you wanted to run mock tests on your lambda_handler you can create another function that runs your code for testing with mocks:

import botocore.session
from botocore.stub import Stubber

def my_s3_function(s3):
    return s3.list_objects(Bucket='test-bucket')

def main_workflow(s3):
    return my_s3_function(s3)

def lambda_handler(event, context):
    s3 = botocore.session.get_session().create_client('s3')
    return main_workflow(s3)

def test_mock_handler(event, context):
    # configure mocks here - for example using stubber for boto3
    s3 = botocore.session.get_session().create_client('s3')
    stubber = Stubber(s3)
    return main_workflow(s3)

The primary concept is that lambda_handler() is only for handling your code when it's run in the full, normal Lambda environment. This code should ideally just do set-up and then invokes other function(s). You can then unit test these isolated functions and write additional handlers to call your code in different test set-ups.

@oneschilling 2018-04-24 19:50:00

If you put unittest.main() in the lambda handler (unittest_lambda_handler), it will not discover your tests and cause the function to always fail since main() is by default calling sys.exit(..) in the end (see https://github.com/python/cpython/blob/master/Lib/unittest/main.py#L273). You can override that behavior with unittest.main(exit=False) but your tests will still not be discovered.

The simplest solution is probably to execute the test directly. So in your example:

def unittest_lambda_handler(event, context):
    unittest.TextTestRunner().run(
        unittest.TestLoader().loadTestsFromTestCase(MyTest))

class MyTest(unittest.TestCase):
    def return_type(self,event, context):
        self.assertTrue(isinstance(
            main_lambda_function.lambda_handler(event, context),int))

@user389955 2018-06-12 20:20:08

this should be the best answer.

@b.b3rn4rd 2018-01-16 22:39:57

Not sure how many people are aware that in most cases you don't even need a 3rd part library to stub boto3 calls. Botocore provides stubber out of the box Reference

This class will allow you to stub out requests so you don't have to hit an endpoint to write tests. Responses are returned first in, first out. If operations are called out of order, or are called with no remaining queued responses, an error will be raised.

@Nathan VÄ“rzemnieks 2018-01-16 18:38:12

localstack may be of interest here.

LocalStack provides an easy-to-use test/mocking framework for developing Cloud applications. Currently, the focus is primarily on supporting the AWS cloud stack.

@Juan Urrego 2018-01-16 18:32:53

Well let's try to divide the question in 2 parts: the unit tests & the integration tests (or the app as a whole). If you are working in a local project, using virtual env, managing your dependencies and using your favourite IDE, you can always run everything in every moment, meaning that if the unit test wants to verify the function add_car(car), well in theory you don't need to test life cycle. I mean, call the handler to redirect to that capability (that would be another test like a component test or, depending on your design, an integration test).

However, what happen if your add_car(car) use dynamo or RDS (any other AWS service)? Well for those cases and for integration & component test you can use placebo: https://github.com/garnaat/placebo. As their description says: "mock boto3 calls that look just like normal calls but actually have no effect at all". There is a really good example in this article: https://serverless.zone/unit-and-integration-testing-for-lambda-fc9510963003. Also there are some other libraries like https://github.com/spulec/moto, you may find examples here https://www.programcreek.com/python/example/105256/moto.mock_ec2

Also, take a look of the recommendations that the guys from ClaudiaJS (I know is Javascript but the concepts are really good) about designing testable Lambdas functions. https://claudiajs.com/tutorials/designing-testable-lambdas.html

Good luck!

@Diego 2018-11-16 10:24:05

which one do you prefer? placebo or moto?

Related Questions

Sponsored Content

8 Answered Questions

[SOLVED] Python unittest - opposite of assertRaises?

18 Answered Questions

[SOLVED] Running unittest with typical test directory structure

  • 2009-12-13 16:10:23
  • Major Major
  • 135258 View
  • 525 Score
  • 18 Answer
  • Tags:   python unit-testing

3 Answered Questions

[SOLVED] Cannot use Requests-Module on AWS Lambda

26 Answered Questions

[SOLVED] Why are Python lambdas useful?

2 Answered Questions

[SOLVED] AWS Lambda - unable to import module 'lambda_function'

1 Answered Questions

[SOLVED] Can't debug unittests in Pycharm

1 Answered Questions

4 Answered Questions

3 Answered Questions

1 Answered Questions

Sponsored Content