Pytest - 模拟 class 实例作为参数传递

Pytest - mocking class instance passed as an argument

假设我有一个简化的 class Object:

class Object:
    def __init__(self, data):
        self.data = data

    def get_data():
        return data.copy()

和独立函数foo

def foo(obj: Object):
    copied_data = obj.get_data()
    ...

我想测试 foo 并使用带有模拟 Object 实例的夹具作为参数传递给 foo。我希望模拟对象 return 一些预定义的数据,所以我也需要模拟它的方法。

我应该如何使用 pytest 以“正确”的方式执行此操作?我不确定如何组合模拟和固定装置。

使用 with statement and the sample patching 文档:

As well as a decorator patch() can be used as a context manager in a with statement:

...

>>> class Class:
...     def method(self):
...         pass
...
>>> with patch('__main__.Class') as MockClass:
...     instance = MockClass.return_value
...     instance.method.return_value = 'foo'
...     assert Class() is instance
...     assert Class().method() == 'foo'
...

我们可以使用 patch() inside a fixture and then yield 模拟实例。

src.py

class Object:
    def __init__(self, data):
        print("Real object initialized")
        self.data = data

    def get_data(self):
        print("Real object get_data")
        return self.data.copy()


def foo(obj: Object):
    print("Object instance:", obj)
    copied_data = obj.get_data()
    return copied_data

test_src.py

from unittest.mock import patch
import pytest

from src import foo, Object


@pytest.fixture
def object_instance():
    with patch('src.Object') as MockClass:
        instance = MockClass.return_value
        instance.get_data.return_value = 'bar'
        yield instance


def test_real_impl():
    object_instance = Object([1, 2])
    assert foo(object_instance) == [1, 2]


def test_mock_impl(object_instance):
    assert foo(object_instance) == 'bar'

输出:

$ pytest -q -rP
================================================================================================= PASSES ==================================================================================================
_____________________________________________________________________________________________ test_real_impl ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
Real object initialized
Object instance: <src.Object object at 0x7fb59ef83820>
Real object get_data
_____________________________________________________________________________________________ test_mock_impl ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
Object instance: <MagicMock name='Object()' id='140418032072736'>
2 passed in 0.06s
  • 如您所见,我们能够创建一个模拟的 Object 并定义其方法的 return 值。