简体   繁体   English

如何模拟一个类并为每组构造函数参数提供一个唯一的对象?

[英]How can I mock a class and provide a unique object for each set of constructor parameters?

I am adding unit tests to a legacy system.我正在向遗留系统添加单元测试。

There is a Manager class that creates Worker objects and performs various operations on them.有一个Manager类可以创建Worker对象并对它们执行各种操作。

I want to mock these workers and verify that the manager is creating and using them correctly.我想模拟这些工人并验证经理是否正确创建和使用它们。

To do this I need to be able to create unique mock objects based on the inputs to the constructor.为此,我需要能够根据构造函数的输入创建唯一的模拟对象。

I have not been able to find the right combination of MagicMock , patch etc. to make this happen.我一直无法找到MagicMockpatch等的正确组合来实现这一点。

So far I have the following which allows me to return a fixed list of custom mock objects for a test:到目前为止,我有以下内容允许我为测试返回自定义模拟对象的固定列表:


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

This allows me to run tests assuming that the manager intends to create worker1 followed by worker2 .这允许我运行测试,假设经理打算创建worker1后跟worker2 This is fine, but inflexible.这很好,但不灵活。

What I would like is for the worker_fixture to be able to construct a unique MagicMock object on the fly based on a call to the Worker constructor, which may occur several times in a test.我希望worker_fixture能够基于对Worker构造函数的调用动态构造一个唯一的 MagicMock 对象,这在测试中可能会发生多次。

The manager class and its tests rely on certain specific properties and methods of the worker, hence I don't believe I can just patch the class like so: manager 类及其测试依赖于 worker 的某些特定属性和方法,因此我不相信我可以像这样修补类:

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

How can I flexibly create mock objects like this?如何灵活地创建这样的模拟对象?

I would patch the class' contructor, to call the get_worker_mock , keep the control of the object instances and patches in your side, I dont think @patch can give you all the behavior you desire.我会修补类的构造get_worker_mock ,调用get_worker_mock ,保持对对象实例和修补程序的控制在你身边,我不认为@patch可以给你你想要的所有行为。

Create a fixture to do so.创建一个装置来做到这一点。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM