Использование unittest.mock.patch в качестве менеджера контекста с фикстурами pytest - PullRequest
0 голосов
/ 05 декабря 2018

Мой пример использования таков: я хочу, чтобы прибор 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'))
...