首页 > 解决方案 > 如何模拟一个类并为每组构造函数参数提供一个唯一的对象?

问题描述

我正在向遗留系统添加单元测试。

有一个Manager类可以创建Worker对象并对它们执行各种操作。

我想模拟这些工人并验证经理是否正确地创建和使用它们。

为此,我需要能够根据构造函数的输入创建独特的模拟对象。

我一直无法找到 等的正确组合MagicMockpatch实现这一点。

到目前为止,我有以下内容允许我返回一个固定的自定义模拟对象列表进行测试:


def get_worker_mock(name, param1):
    worker = MagicMock(spec=Worker)
    worker.name = name
    worker.param1 = param1
    worker.method1.return_value = "mock_method1_val"
    worker.method2.return_value = "mock_method2_val"
    return worker

@pytest.fixture(autouse=True)
def worker_fixture():
    with patch("mypackage.manager.Worker", spec=Worker) as fixture:
        worker1 = get_worker_mock("Worker1", 1)
        worker2 = get_worker_mock("Worker2", 2)

        fixture.side_effect = [worker1, worker2]
        yield fixture

这允许我运行测试,假设经理打算创建worker1后跟worker2. 这很好,但不灵活。

我想要的worker_fixture是能够基于对构造函数的调用动态构造一个唯一的 MagicMock 对象Worker,这可能在测试中发生多次。

manager 类及其测试依赖于 worker 的某些特定属性和方法,因此我不相信我可以像这样修补类:

@patch("mypackage.Worker", autospec=True)
def test_some_manager_test(self, worker_patch):
    # Test using the mock...

我怎样才能灵活地创建这样的模拟对象?

标签: pythonunit-testingmocking

解决方案


我会修补类的构造函数,调用get_worker_mock,保持对对象实例和补丁的控制在你身边,我认为@patch不能给你所有你想要的行为。

为此创建一个夹具。

@pytest.fixture
def patch_worker(monkeypatch):
    monkeypatch.setattr(mypackage.manager, 'Worker', get_worker_mock)

推荐阅读