简体   繁体   English

如何使用 pytest fixtures 优雅地模拟 class?

[英]How to elegantly mock a class using pytest fixtures?

Let's say I have a fixture to mock a class using monkeypatch .假设我有一个使用 monkeypatch 模拟monkeypatchfixture

# conftest.py
@pytest.fixture
def mock_dummyclass(monkeypatch):
    def mock_function():
        return None
 
    monkeypatch.setattr(dummypackage, "dummyclass", mock_function)

Now, I have to use this fixture in my test so that this class is mocked.现在,我必须在我的测试中使用这个夹具,以便模拟这个 class。

#test_dummy.py
@pytest.mark.usefixtures("mock_dummyclass")
class TestManyDummyMethods:
    def test_dummy_one():
        import dummypackage  # Flag A
    def test_dummy_two():
        import dummypackage  # Flag B
    ...
    def test_dummy_n():
        import dummypackage  # Flag N

As you can see in the flagged lines, that I'll have to import this module dummypackage inside every function to ensure that the fixture is applied before the module is imported (otherwise the fixture would not be effective).正如您在标记行中看到的那样,我必须在每个 function 中导入此模块dummypackage以确保在导入模块之前应用夹具(否则夹具将无效)。

Importing dummypackage inside the class would work but calling self.dummypackage inside functions doesn't seem very elegant either.在 class 中导入dummypackage会起作用,但在函数内部调用self.dummypackage似乎也不是很优雅。

Is there a more elegant way to achieve this?有没有更优雅的方法来实现这一目标?

Comment: The monkeypatch library doesn't seem to be maintained anymore.评论: monkeypatch库好像没人维护了。 unittest.mock should probably offer all you need. unittest.mock应该可以提供你所需要的一切。

I would try to avoid a solution that depends on importing the module as part of your test because that would break if it was imported for another reason (eg import other functions).我会尽量避免依赖于导入模块作为测试的一部分的解决方案,因为如果它是出于其他原因导入的(例如导入其他函数),那将会中断。

I am using os as an example as that exists and makes it reproducible.我以os为例,因为它存在并使其可重现。

How best to patch seem to depend on how you import from another module.如何最好地修补似乎取决于您如何从另一个模块导入。

Example 1: target_module1.py (importing the join method from os.path ):示例 1: target_module1.py (从os.path导入join方法):

from os.path import join

def some_method_using_join():
    return join('parent', 'child')

This requires us to patch the join method of target_module1.py :这需要我们修补target_module1.pyjoin方法:

target_module1_test.py : target_module1_test.py

from unittest.mock import patch, MagicMock

import pytest

from target_module1 import some_method_using_join

@patch('target_module1.join')
def some_test(join_mock: MagicMock):
    some_method_using_join()

Example 2: target_module2.py (importing the os module):示例2: target_module2.py (导入os模块):

import os

def some_method_using_join():
    return os.path.join('parent', 'child')

This allows us to patch the join method on os.path :这允许我们修补os.path上的join方法:

target_module2_test.py : target_module2_test.py

from unittest.mock import patch, MagicMock

import pytest

from target_module2 import some_method_using_join

@patch('os.path.join')
def some_test(join_mock: MagicMock):
    some_method_using_join()

This assumes that you don't need to patch a class or method that is used at the module level (ie while importing).这假定您不需要修补 class 或在模块级别(即导入时)使用的方法。

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

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