如何使用 moto 库模拟硬依赖

How to mock hard dependency using moto library

我正在尝试使用 moto 在 python 代码中模拟 acm 客户端,但它似乎不起作用。来自依赖注入的心态,我不清楚这个模拟装饰器的想法。

def handle_custom_resource_request(event, context):
        try:
            cert_arn = event['PhysicalResourceId']
            acm_client.delete_certificate(CertificateArn=cert_arn)
        except Exception as e:
            pass
        finally:
            pass
@mock_acm
def test_handle_custom_resource_request():
    event = {
        'RequestType': 'Delete',
        'PhysicalResourceId': 'arn:aws:acm:eu-west-1:123456789:certificate/DummyCertificate',
        'ResponseURL': 'http://localhost'
    }
    context = {}
    response = cert_requester.handle_custom_resource_request(event, context)
    print(response)

我想模拟这个 acm 客户端,它应该 return 一个 True 值,例如当 delete_certificate 方法被调用时。然而,在这个测试中似乎没有发生模拟,我收到以下错误

botocore.exceptions.ClientError: An error occurred (ExpiredTokenException) when calling the DeleteCertificate operation: The security token included in the request is expired

有没有办法像我们在其他语言测试框架中那样模拟 return 值。

为避免您的测试接触到 AWS,必须在创建任何 boto3 客户端之前启动模拟。

根据您的示例代码,最简单的方法是简单地移动导入:

@mock_acm
def test_handle_custom_resource_request():
    import cert_requester
    event = {
        'RequestType': 'Delete',
        'PhysicalResourceId': 'arn:aws:acm:eu-west-1:123456789:certificate/DummyCertificate',
        'ResponseURL': 'http://localhost'
    }
    context = {}
    response = cert_requester.handle_custom_resource_request(event, context)
    print(response)

文档对此有更多信息: http://docs.getmoto.org/en/latest/docs/getting_started.html#what-about-those-pesky-imports


I want to mock this acm client that it should return a value of True for example when the delete_certificate method is called.

将 Moto 视为 AWS 的本地离线版本。当你有一个通过 AWS 的单元测试时,使用 boto3-requests 来验证它做了它应该做的事情,你可以在上面添加 mock_..-decorator。有了装饰器,您可以相信测试仍然会验证行为是否正确,但没有 运行 它针对 AWS 的成本。

比如想知道某个证书是否删除成功,可以使用如下boto3-requests:

  • 调用 describe_certificate,并验证它抛出错误(因为它不再存在)
  • 调用 list_certificates,确认已删除的证书不再显示

所以最终的测试可能看起来像这样:

def test_handle_custom_resource_request():
    # GIVEN
    # A certificate exists

    # WHEN
    # Our business logic should delete the certificate with that ARN
    import cert_requester
    event = {
        'RequestType': 'Delete',
        'PhysicalResourceId': 'arn:aws:acm:eu-west-1:123456789:certificate/DummyCertificate',
        'ResponseURL': 'http://localhost'
    }
    context = {}
    response = cert_requester.handle_custom_resource_request(event, context)
    print(response)

    # THEN
    # the certificate should be deleted
    certificates = boto3.client("acm").list_certificates()
    assert "DummyCertificate" not in certificates