3

I have a python function that invokes an AWS Lambda function.

#lambda.py
import boto3
import os

client    = boto3.client('lambda')
MY_LAMBDA = os.environ['MY_LAMBDA']

def invoke_function(input):
    response = client.invoke(
        FunctionName=MY_LAMBDA,
        InvocationType='RequestResponse',
        Payload=json.dumps(input)
    )

How can I create a Unit Test for this function? I have been using Moto for other AWS services, but haven't been able to make it work for Lambda.

My attempt at using moto:

#test_lambda.py

from unittest.mock import MagicMock, patch
from unittest.mock import ANY
from moto import mock_lambda
import boto3
import os
import zipfile
import io
import lambda

class LambdaTest(unittest.TestCase):

    def get_test_zip_file(self):
        pfunc = '''
                def lambda_handler(event, context):
                    return event
                '''
        zip_output = io.BytesIO()
        zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED)
        zip_file.writestr('lambda_function.py', pfunc)
        zip_file.close()
        zip_output.seek(0)
        return zip_output.read()

    @mock_lambda
    def test_invoke_requestresponse_function(self):
        conn = boto3.client('lambda', 'us-east-1')
        conn.create_function(
            FunctionName='test-func',
            Runtime='python3.8',
            Role='test-iam-role',
            Handler='lambda_function.lambda_handler',
            Code={
                'ZipFile': self.get_test_zip_file(),
            },
            Description='test lambda function',
            Timeout=3,
            MemorySize=128,
            Publish=True
        )

        sample_input = {'msg': 'Test Input'}

        result = lambda.invoke_function(sample_input)

This errors out with:

botocore.exceptions.ClientError: An error occurred (404) when calling the Invoke operation: 
mallocator4
  • 31
  • 1
  • 3

1 Answers1

2

The boto3-client in lambda.py is initialized before any of the mocking takes place. As that client doesn't know it's being mocked, it probably tries to talk to AWS itself.

For you particular test case, there are a few solutions:

  • Place import lambda in the test itself, so that the boto3-client is created after the decorators have initialized
  • Override the client with the mocked version: lambda.client = conn
  • Pass the mocked client as an argument to lambda.invoke_function(conn, sample_input)
Bert Blommers
  • 1,788
  • 2
  • 13
  • 19