如何复用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
相关产品推荐
相关产品推荐

