【问题标题】:Overriding boto3 client with stubbed client用存根客户端覆盖 boto3 客户端
【发布时间】:2021-01-28 21:46:14
【问题描述】:

有很多资源可用于使用 pytest、Moto 和 botocore Stubber 编写单元测试。

编辑。在进一步调查后,我重新表述了这个问题:

我有一个lambda_function python 脚本,我想用 pytest 和 Boto Stubber 对其进行测试。在lambda_function 内部,我从另一个 python 文件中导入了一个 ssm_client (ssm_clt = boto3.client('ssm', region_name=region))

问题是当我像这样设置 pytest 时:

def test_lambda_handler(ssm_stubber):
    ssm_stubber.activate()
    ssm_stubber.add_response(
        'get_parameters_by_path',
        expected_params={'Path': 'my/ssm/parameter', 'Recursive': 'True'},
        service_response={
            'Parameters': [
                {
                    'Name': 'my/ssm/parameter',
                    'Type': 'String',
                    'Value': 'my_string returned',
                },
            ],
        },
    )
    ssm_stubber.deactivate()

    ssm_stubber.assert_no_pending_responses()

ssm_stubber 定义为 pytest 夹具:

@pytest.fixture(autouse=True)
def ssm_stubber():
    with Stubber(clients.ssm_clt) as stubber:
        yield stubber

它使用实际的 boto3 客户端而不是 stubber 客户端,因为我在 lambda_function 中有一个导入语句。我正在努力解决这个问题。我不想在仅用于测试的常规lambda_function 中放入一堆代码。

这几乎就像我需要一个条件导入,但据我所知这是不好的做法。

我是否以一种几乎不可能以这种方式将 stubber 与 pytest 一起使用的方式来构建我的项目?

【问题讨论】:

    标签: aws-lambda pytest


    【解决方案1】:

    所以我最终只使用了 pytest 的 monkeypatch 功能。这比尝试修补 Boto 3 客户端并使其正确存根要简单得多。下面是我所做的一些示例代码。

    这是我要测试的功能。问题是来自param_dictionary = setup.get_ssm_parameters() 函数的AWS API 调用从未被正确地存根。这没有被存根,因为它超出了测试正在测试的功能。这导致它在测试期间尝试使用真正的 boto3 客户端调用。 lambda_handler 中的所有其他 API 调用总是被正确地存根。

    """lambda_function.py"""
        import another_function
    
        # this was the function that has an SSM AWS client call in it that wasn't get properly stubbed because it is outside of the function I am testing but is still executed as part of the script    
        param_dictionary = another_function.get_ssm_parameters()
    
        def lambda_handler(event, context):
            # other code here that runs fine and AWS API calls that are properly stubbed
    

    这是包含对参数存储的 AWS API 调用的文件。

    """another_function.py"""
    import boto3
    
    ssm_clt = boto3.client('ssm', region_name='us-west-2')
    
    def get_ssm_parameters()
        param_dict = {}
        ssm_resp = ssm_clt.get_parameters_by_path(
            Path=f'/{os.environ["teamName"]}/{os.environ["environment"]}/etl',
            Recursive=True
        )
        
        for parameter in ssm_resp["Parameters"]:
            param_dict.update(json.loads(parameter["Value"]))
    
        return param_dict 
    

    这是我的测试。你可以看到我传入了金钱补丁 pytest.fixture,它将修补来自函数 get_ssm_parameters() 的响应,因此它不会进行 API 调用。

    """test_lambda_function.py"""
    def test_my_func_one(return_param_dict):
        from lambda_function import lambda_handler
    
        # insert other snubbers and "add_response" code here for AWS API calls that occur inside of the lambda_handler
    
        lambda_handler('my_event', None)
    

    这是 pytest 的配置文件,我在其中设置了猴子补丁。我使用monkeypatch 的setattr 功能来覆盖get_ssm_parameters() 的返回。这个返回定义在函数param_dict()

    """conftest.py"""
    import pytest
    import another function
    def param_dict():
        param_dict = {"my_key": "my_value"}
    
        return param_dict
    
    
    @pytest.fixture(autouse=True)
    def return_param_dict(monkeypatch):
        monkeypatch.setattr(another_function, "get_ssm_parameters", param_dict)
    

    最终,这比尝试在我正在测试的功能之外的另一个模块中修补客户端要简单得多。

    【讨论】:

      猜你喜欢
      • 2011-03-23
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      • 2016-10-06
      • 2020-03-22
      相关资源
      最近更新 更多