There are a lot of resources out there for using pytest, Moto, and botocore Stubber to write unit tests.
I believe I have set things up correctly, but I keep getting SSL validation errors, which mean that my AWS API calls are not being prevented from trying to contact the actual AWS service.
Here is my project structure:
- my_lambda_name
-> lambda_function.py
- test
-> test_my_lambda_name.py
-> conftest.py
- layers
-> shared_layer
-> python
-> clients.py
inside the clients.py
file:
import boto3
ssm_clt = boto3.client('ssm', region_name='us-east-2')
here are the contents of the conftest.py
file:
import pytest
from botocore.stub import Stubber, ANY
import clients
@pytest.fixture(autouse=True)
def ssm_stub():
with Stubber(clients.ssm_clt) as stubber:
yield stubber
inside of my lambda_function.py
:
import setup
# get parameter dict from ssm
param_dict = setup.get_parameter_dict()
inside of setup.py
file:
import json
from clients import ssm_clt
def get_parameter_dict():
param_dict = {}
ssm_resp = ssm_clt.get_parameters_by_path(
Path=f'/{os.environ["teamName"]}/{os.environ["environment"]}/string_here',
Recursive=True
)
for parameter in ssm_resp["Parameters"]:
param_dict.update(json.loads(parameter["Value"]))
log.log_function_results(func_frame_obj, "success")
return param_dict
and finally, here is the test I'm trying to run inside of test_my_lambda_name.py
:
import pytest
import os
from my_lambda_name import lambda_function
good_event_input = {"my_key": "my_value"}
def test_lambda_handler(ssm_stub):
ssm_stub.add_response(
'get_parameters_by_path',
expected_params={'Path': 'my/path/to/param', 'Recursive': 'True'},
service_response={
'Parameters': [
{
'Name': 'my/path/to/param/here',
'Type': 'String',
'Value': 'my string value',
},
],
},
)
result = lambda_function.lambda_handler(good_event_input, 'my_string')
assert result is None
When I run pytest, it seems to find the correct lambda python file to run and does indeed call get_parameter_dict()
because I see it in the logs, but then it fails with this error:
botocore.exceptions.SSLError: SSL validation failed for
https://ssm.us-east-2.amazonaws.com/ [Errno 2] No such file or
directory
So this makes me think that it is trying to go outside and not mock the response locally. But why?
EDIT:
So I think what is happening is when the get_parameters_by_path()
is being called within lambda_function.py
it not using the Stubber, but the real client.
I've read a bit that I could patch this with mock?
I might have multiple AWS calls in some of my tests so I don't want to have to patch each API call, could I just do something like this?
good_event_input = {"my_key": "my_value"}
@patch('boto3.client')
def test_lambda_handler(ssm_stub):
ssm_stub.add_response(
'get_parameters_by_path',
expected_params={'Path': 'my/path/to/param', 'Recursive': 'True'},
service_response={
'Parameters': [
{
'Name': 'my/path/to/param/here',
'Type': 'String',
'Value': 'my string value',
},
],
},
)
result = lambda_function.lambda_handler(good_event_input, 'my_string')
assert result is None
Is it possible to patch all boto3 clients created that are used in one test?