You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复用pytest-mock中的重复Mock类代码?

如何避免测试中重复Mock PyWaves类?

我有多个测试方法需要Mock PyWaves类,目前这段Mock代码在最后3个测试方法里重复出现:

class PyWaves(object):
    def names(self):
        return test_class_self.mock_wave_names()

我尝试把这段代码移到测试类的__init__方法中,但没能生效。请问避免在需要该Mock的每个方法中重复编写代码的正确方式是什么?

以下是我的测试类代码:

class TestExtractedXPSNameAdapter:

    # def __init__(self, mocker):
    #     class PyWaves(object):
    #         def names(self):
    #             return self.mock_wave_names()
    #     self.waves = PyWaves()


    def mock_wave_names(self): 
        return ['net_a', 'top.net_b', 'top.foo@bar@net1#foo@bar@inst@0_g', 'top.foo1@bar1@net2#foo1@bar1@inst1_d']
    
    def expected_index(self): 
        return {'net_a': 'net_a', 'top.net_b': 'top.net_b', 'foo@bar@inst@0_g': 'top.foo@bar@net1#foo@bar@inst@0_g', 'foo1@bar1@inst1_d': 'top.foo1@bar1@net2#foo1@bar1@inst1_d'}

    def test_gen_populated_name_guesses(self):
        adapter = ExtractedXPSNameAdapter()
        identifier = WaveformIdentifier(instance_name="my_inst", path="/i_macro/sub1/sub2", term_name="my_terminal")
        guesses = adapter.gen_name_guesses(identifier)
        expected_guesses = [
            "i_macro@sub1@sub2@my_inst@0_my_terminal",
            "i_macro@sub1@sub2@my_inst_my_terminal",
            ]
        assert guesses == expected_guesses

    def test_gen_empty_name_guesses(self):
        adapter = ExtractedXPSNameAdapter()
        identifier = WaveformIdentifier(instance_name="my_inst", path="/i_macro/sub1/sub2")
        guesses = adapter.gen_name_guesses(identifier)
        expected_guesses = []
        assert guesses == expected_guesses

    def test_build_index(self, mocker):
        test_class_self = self
        class PyWaves(object):
            def names(self):
                return test_class_self.mock_wave_names()
        waves = PyWaves()
        adapter = ExtractedXPSNameAdapter()
        adapter.set_wave_list(waves)
        adapter.build_index()
        assert adapter.index == self.expected_index()

    def test_waveform_name(self, mocker):
        test_class_self = self
        class PyWaves(object):
            def names(self):
                return test_class_self.mock_wave_names()
        waves = PyWaves()
        adapter = ExtractedXPSNameAdapter()
        adapter.set_wave_list(waves)
        identifier = WaveformIdentifier(instance_name='inst1', path='/foo1/bar1', term_name="d")
        name = adapter.waveform_name(identifier)
        assert name == 'top.foo1@bar1@net2#foo1@bar1@inst1_d'

    def test_info_from_identifier(self, mocker):
        test_class_self = self
        class PyWaves(object):
            def names(self):
                return test_class_self.mock_wave_names()
        waves = PyWaves()
        adapter = ExtractedXPSNameAdapter()
        adapter.set_wave_list(waves)
        identifier = WaveformIdentifier(instance_name='inst1', path='/foo1/bar1', term_name="d")
        expected = WaveformNameInfo(identifier=identifier, type=identifier.type, full_name='top.foo1@bar1@net2#foo1@bar1@inst1_d', path=identifier.path, terminal_name=identifier.term_name)
        assert adapter.info_from_identifier(identifier) == expected

解决方法

为什么__init__方法无效?

pytest测试类的__init__不会自动接收fixture参数(比如mocker),且pytest实例化测试类时不会传递fixture,所以放在__init__里无法正常初始化Mock对象。

方案1:使用setup_method初始化Mock

在测试类中添加setup_method方法,每个测试方法执行前自动初始化Mock的PyWaves实例,避免重复代码:

class TestExtractedXPSNameAdapter:
    def setup_method(self, method, mocker):
        # 定义Mock的PyWaves类
        class PyWaves(object):
            def names(self):
                return self.mock_wave_names()
        self.waves = PyWaves()

    # 保留原有mock_wave_names、expected_index方法...

    def test_build_index(self, mocker):
        adapter = ExtractedXPSNameAdapter()
        adapter.set_wave_list(self.waves)  # 直接复用setup中初始化的waves
        adapter.build_index()
        assert adapter.index == self.expected_index()

    # 其他需要Mock的测试方法同理,直接使用self.waves即可

方案2:用pytest-mock直接Mock方法(更简洁)

无需手动定义PyWaves类,直接用mocker创建Mock对象并指定返回值:

def test_build_index(self, mocker):
    # 创建Mock对象并指定names方法的返回值
    pywaves_mock = mocker.Mock()
    pywaves_mock.names.return_value = self.mock_wave_names()
    
    adapter = ExtractedXPSNameAdapter()
    adapter.set_wave_list(pywaves_mock)
    adapter.build_index()
    assert adapter.index == self.expected_index()

这种方式完全避免了重复定义类的代码,更符合pytest-mock的使用规范。

方案3:封装成pytest fixture(跨测试类复用)

如果多个测试类都需要这个Mock,可以把它封装成fixture放在conftest.py中:

# conftest.py
import pytest
from your_test_module import TestExtractedXPSNameAdapter

@pytest.fixture
def mock_pywaves():
    class PyWaves(object):
        def names(self):
            return TestExtractedXPSNameAdapter().mock_wave_names()
    return PyWaves()

然后在测试方法中直接注入这个fixture:

def test_build_index(self, mock_pywaves):
    adapter = ExtractedXPSNameAdapter()
    adapter.set_wave_list(mock_pywaves)
    adapter.build_index()
    assert adapter.index == self.expected_index()

内容的提问来源于stack exchange,提问作者nPn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:34:56