Moto 似乎并没有在 pytest 中模拟 aws 交互

Stu*_*Cat 6 python amazon-web-services pytest boto3 moto

假设我想嘲笑以下内容:

session = boto3.Session(profile_name=profile)
resource = session.resource('iam')
iam_users = resource.users.all()
policies = resource.policies.filter(Scope='AWS', OnlyAttached=True, PolicyUsageFilter='PermissionsPolicy')
Run Code Online (Sandbox Code Playgroud)

我该如何开始在 pytest 中模拟这个?我可以通过创建虚拟类和必要的属性来创建模拟对象,但我怀疑这是错误的方法。

一些额外的细节,这是我正在尝试测试的:

def test_check_aws_profile(self, mocker):
    mocked_boto3 = mocker.patch('myapp.services.utils.boto3.Session')
    mocker.patch(mocked_boto3.client.get_caller_identity.get, return_value='foo-account-id')
    assert 'foo-account-id' == my_func('foo')

#in myapp.services.utils.py
def my_func(profile):
    session = boto3.Session(profile_name=profile)
    client = session.client('sts')
    aws_account_number = client.get_caller_identity().get('Account')
    return aws_account_number
Run Code Online (Sandbox Code Playgroud)

但我似乎无法正确地修复这个问题。我正在尝试这样做,以便我可以修补会话和该方法中的函数调用

我尝试使用 moto 并得到了这个:

@mock_sts
def test_check_aws_profile(self):
    session = boto3.Session(profile_name='foo')
    client = session.client('sts')
    client.get_caller_identity().get('Account')
Run Code Online (Sandbox Code Playgroud)

但我遇到了

>           raise ProfileNotFound(profile=profile_name)
E           botocore.exceptions.ProfileNotFound: The config profile (foo) could not be found
Run Code Online (Sandbox Code Playgroud)

所以看起来它并没有嘲笑任何东西:|

编辑:

事实证明,您需要在配置和凭据文件中包含模拟凭据才能使其工作。

amp*_*and 5

如果您想使用moto,可以使用AWS_SHARED_CREDENTIALS_FILE环境变量,将其指向可以保存在测试文件夹中的虚拟凭据文件。您可以在那里定义您的配置文件。例子:

文件:test_stuff.py. dummy_aws_credentials

测试内容.py:

import os
from pathlib import Path
import boto3
import pytest
from moto import mock_sts


@pytest.fixture(scope='module')
def aws_credentials():
    """Mocked AWS Credentials for moto."""
    moto_credentials_file_path = Path(__file__).parent.absolute() / 'dummy_aws_credentials'
    os.environ['AWS_SHARED_CREDENTIALS_FILE'] = str(moto_credentials_file_path)


@mock_sts
def test_check_aws_profile(aws_credentials):
    session = boto3.Session(profile_name='foo')
    client = session.client('sts')
    client.get_caller_identity().get('Account')
Run Code Online (Sandbox Code Playgroud)

虚拟_aws_凭证:

[foo]
aws_access_key_id = mock
aws_secret_access_key = mock
Run Code Online (Sandbox Code Playgroud)


avy*_*ysk 3

我不确定你到底想要什么,所以我会给你一些开始的东西。

unittest.mock例如,你可以为你嘲笑一切。(有用的阅读:https://docs.python.org/3/library/unittest.mock.html

module.py:

import boto3

def function():
    session = boto3.Session(profile_name="foobar")
    client = session.resource("sts")
    return client.get_caller_identity().get('Account')
Run Code Online (Sandbox Code Playgroud)

test_module.py:

from unittest.mock import patch

import module

@patch("module.boto3")  # this creates mock which is passed to test below
def test_function(mocked_boto):
    # mocks below are magically created by unittest.mock when they are accessed
    mocked_session = mocked_boto.Session()
    mocked_client = mocked_session.resource()
    mocked_identity = mocked_client.get_caller_identity()

    # now mock the return value of .get()
    mocked_identity.get.return_value = "foo-bar-baz"

    result = module.function()
    assert result == "foo-bar-baz"

    # we can make sure mocks were called properly, for example
    mocked_identity.get.assert_called_once_with("Account")

Run Code Online (Sandbox Code Playgroud)

pytest运行结果:

$ pytest
================================ test session starts ================================
platform darwin -- Python 3.7.6, pytest-5.3.2, py-1.8.1, pluggy-0.13.1
rootdir: /private/tmp/one
collected 1 item                                                                    

test_module.py .                                                              [100%]

================================= 1 passed in 0.09s =================================
Run Code Online (Sandbox Code Playgroud)

我还建议安装pytest-socket并运行pytest --disable-socket以确保您的测试不会意外与网络通信。