将unittest.mock.patch用作带有pytest固定装置的上下文管理器

时间:2018-12-04 21:11:43

标签: unit-testing pytest python-unittest python-unittest.mock

我的用例是这样的:我希望pytest固定装置返回一个类,该类的依赖关系已被模拟以返回不同的可配置值。

测试对象为Subject类。它取决于模块boto3。我想对其进行模拟,以便在我调用boto3.client('codepipeline')时会返回一个模拟对象,该对象配置为以某种方式运行。

出于测试目的,我想在其上调用'foo()'函数并返回可配置的响应。

在这种情况下,我将其配置为返回字符串“ bar”。

我正在尝试将unittest.mock.patch用作pytest固定装置内的上下文管理器,并且无法正常工作。

演示代码:

#subject.py
import boto3


class Subject:
    def __init__(self):
        self.codepipeline_client = boto3.client('codepipeline')

    def foo(self):
        return self.codepipeline_client.foo()


#test_subject.py
from unittest.mock import patch, NonCallableMagicMock

import pytest
from expects import expect, equal

import subject


@pytest.fixture
def mocked_subject_factory():
    def _boto3_client_mock(aws_service, foo):
        client = None
        if aws_service == 'codepipeline':
            client = NonCallableMagicMock(name='codepipeline_client')
            client.foo.return_value = foo
        return client

    def _factory(foo):
        with patch('subject.boto3.client') as mock_client:
            mock_client.side_effect = _boto3_client_mock(foo=foo)
            yield subject.Subject()

    return _factory


class TestSubject:

    def test_passing_foo(self, mocked_subject_factory):
        s = mocked_subject_factory(foo='mocked foo value')
        print(s)
        expect(s.foo()).to(equal('mocked foo value'))

如果我运行pytest -s test_subject.py,我会得到:

================================================= test session starts ==================================================
platform linux -- Python 3.7.0, pytest-3.8.2, py-1.6.0, pluggy-0.7.1
rootdir: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX, inifile:
collected 1 item

test_subject.py <generator object mocked_subject_factory.<locals>._factory at 0x7f246255d840>
F

======================================================= FAILURES =======================================================
_____________________________________________ TestSubject.test_passing_foo _____________________________________________

self = <test_subject.TestSubject object at 0x7f24624e0940>
mocked_subject_factory = <function mocked_subject_factory.<locals>._factory at 0x7f24624e36a8>

    def test_passing_foo(self, mocked_subject_factory):
        s = mocked_subject_factory(foo='mocked foo value')
        print(s)
>       expect(s.foo()).to(equal('mocked foo value'))
E       AttributeError: 'generator' object has no attribute 'foo'

test_subject.py:31: AttributeError

编辑1:我按照注释中的@hoefling的说明进行了以下测试,但结果相同:

from unittest.mock import patch, NonCallableMagicMock

import pytest
from expects import expect, equal

import subject


@pytest.fixture
def mocked_subject_factory():
    def _boto3_client_mock(aws_service, foo):
        client = None
        if aws_service == 'codepipeline':
            client = NonCallableMagicMock(name='codepipeline_client')
            client.foo.return_value = foo
        return client

    with patch('subject.boto3.client') as mock_client:
        def _factory(foo):
            mock_client.side_effect = _boto3_client_mock(foo=foo)
            yield subject.Subject()

        yield _factory


class TestSubject:

    def test_passing_foo(self, mocked_subject_factory):
        print(mocked_subject_factory)
        s = mocked_subject_factory(foo='mocked foo value')
        print(s)
        expect(s.foo()).to(equal('mocked foo value'))

0 个答案:

没有答案