首页 > 解决方案 > 如何使用 pytest 设备优雅地模拟一个类?

问题描述

假设我有一个fixture使用monkeypatch.

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

现在,我必须在我的测试中使用这个夹具,以便模拟这个类。

#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

正如您在标记行中看到的那样,我必须dummypackage在每个函数中导​​入此模块,以确保在导入模块之前应用夹具(否则夹具将无效)。

在类内部导入dummypackage会起作用,但self.dummypackage在内部调用函数似乎也不是很优雅。

有没有更优雅的方法来实现这一点?

标签: pythonpytestfixtures

解决方案


评论:monkeypatch图书馆似乎不再维护了。unittest.mock应该可以提供你所需要的一切。

我会尽量避免依赖于将模块作为测试的一部分导入的解决方案,因为如果出于其他原因(例如导入其他功能)导入它会中断。

我正在使用os作为示例,因为它存在并使其可重现。

如何最好地修补似乎取决于您如何从另一个模块导入。

示例 1:(从target_module1.py导入join方法os.path):

from os.path import join

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

这需要我们修补以下join方法target_module1.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()

示例 2:(target_module2.py导入os模块):

import os

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

这允许我们修补join方法os.path

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()

这假设您不需要修补在模块级别(即在导入时)使用的类或方法。


推荐阅读