【问题标题】:Mocking AWS session.Session() got AttributeError: 'function' object has no attribute 'call_count'?模拟 AWS session.Session() got AttributeError: 'function' object has no attribute 'call_count'?
【发布时间】:2022-01-25 02:48:34
【问题描述】:

我需要为下面的类函数编写单元测试,它返回 AWS 的 EC2 实例,以进行测试。

class C:
    def f(cls, session, filters):
            # ....
            instances = session.resource('ec2').instances.filter(Filters=filters)
            # ....
            return instances

我想测试是否使用参数Filters=filters 调用session.resource('ec2').instances.filter()

import boto3
import boto3.session
import pytest
from moto import mock_ec2

@mock_ec2
def test_get_nodes():
    '''Test get node'''
    session = boto3.session.Session(region_name='')
    filters = None
    C.f(session, filters)
    assert session.resource('ec2').instances.filter.call_count == 1

但是,测试出现以下错误?

> raise ValueError("无效端点:%s" % endpoint_url) E ValueError:无效端点:https://ec2..amazonaws.com

我实际上不希望测试函数连接到 AWS 控制台。无论如何,在我将region_name 设置为适当的值后,它得到了以下错误:

> 断言 session.resource('ec2').instances.filter.call_count == 1 E AttributeError: 'function' 对象没有属性 'call_count'

【问题讨论】:

    标签: python amazon-web-services pytest boto3 moto


    【解决方案1】:

    您似乎正在尝试将传统的模拟方法(如测试调用次数、捕获参数等)与 Moto 结合使用。但 Moto 并未公开任何此类信息。

    Moto 更像是内存中的 AWS 实例。这意味着您可以使用任何(受支持的)boto3 请求,而 Moto 会拦截该请求并像 AWS 一样行事 - 但不会实际发出请求(并产生任何费用)。

    传统的 Moto 测试用例(伪用例)如下所示:

    assert len(session.resource('ec2').instances) == 0
    ec2_client.run_instances(..)
    assert len(session.resource('ec2').instances) == 2
    assert len(session.resource('ec2').instances.filter) == 1
    

    这些都不检查是否调用了方法 - 它使用 boto3-requests 来验证以前的 boto3-requests 是否成功,就像您正在编写针对 AWS 本身的集成测试一样。

    编辑:
    如果您担心向 AWS 本身发出请求,则值得设置虚拟环境变量以在测试期间重置您的访问密钥/秘密密钥。
    http://docs.getmoto.org/en/latest/docs/getting_started.html#recommended-usage

    也可以使用不存在的区域,更加安心。

    os.environ["MOTO_ALLOW_NONEXISTENT_REGION"] = True
    os.environ["AWS_DEFAULT_REGION"] = "antarctica"
    

    在此处查看常见问题解答: http://docs.getmoto.org/en/latest/docs/faq.html#can-i-mock-the-default-aws-region

    【讨论】:

    • 我的问题中的函数C.f() 刚刚查询了AWS。那么assert len(session.resource('ec2').instances) == 0不会告诉函数是否调用了查询函数?
    • 正确 - 不在 Moto 范围内
    • 好的。谢谢。我可能不得不使用传统的猴子补丁进行测试。
    • os.environ["MOTO_ALLOW_NONEXISTENT_REGION"] = True 引发错误。我把它改成了os.environ["MOTO_ALLOW_NONEXISTENT_REGION"] = "True"
    【解决方案2】:

    这里没有设置区域:

    session = boto3.session.Session(region_name='')
    

    尝试填写区域。

    【讨论】:

    • 会话将被模拟,因此区域无关紧要。我实际上不希望测试函数连接到 AWS 控制台。
    • 我已经用region_name 集合更新了问题。
    • 你到底想在这里断言什么?过滤器没有“call_count”属性。 boto3.amazonaws.com/v1/documentation/api/latest/reference/…
    • 我想模拟会话对象;所以在单元测试中,我想确保C.f(session, filters)的执行调用session.resource('ec2').instances.filter()一次。
    • 那么这可能就足够了:instance = C.f(session, filters) assert instance is not None 如果你打印instance,你会得到这个:ec2.instancesCollection(ec2.ServiceResource(), ec2.Instance)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    • 2020-04-26
    • 2020-11-21
    • 1970-01-01
    • 2022-12-15
    • 2022-12-27
    相关资源
    最近更新 更多