使用 pytest.fixture 返回模拟对象的正确方法

Bry*_*eng 17 python unit-testing pytest python-3.x python-unittest

我正在尝试设置被测目标@pytest.fixture并在模块中的所有测试中使用它。我能够正确修补测试,但是在我添加@pytest.fixture返回模拟对象并在其他单元测试中调用模拟对象后,该对象开始引用回原始函数。

以下是我拥有的代码。我期望mocked_worker单元测试中的 引用返回值,但它正在调用实际os.getcwd方法。

请帮我更正代码:

import os
import pytest
from unittest.mock import patch

class Worker:
    def work_on(self):
        path = os.getcwd()
        print(f'Working on {path}')
        return path

@pytest.fixture()
def mocked_worker():
    with patch('test.test_module.os.getcwd', return_value="Testing"):
        result = Worker()
    return result

def test_work_on(mocked_worker):
    ans = mocked_worker.work_on()
    assert ans == "Testing"
Run Code Online (Sandbox Code Playgroud)

eyl*_*esc 27

问题在于,当工作人员返回“with”语句的范围结束使对象取其实际值时,解决方案是使用“yield”。

@pytest.fixture()
def mocked_worker():
    with patch('test.test_module.os.getcwd', return_value="Testing"):
        result = Worker()
        yield result
Run Code Online (Sandbox Code Playgroud)

  • 你让我免于大量的调试时间.. (2认同)

The*_*Hog 9

我建议使用pytest-mock。因此,使用此库的一个文件 (test_file.py) 解决方案的完整示例是:

import os
import pytest
from unittest.mock import patch

class Worker:
    def work_on(self):
        path = os.getcwd()
        print(f'Working on {path}')
        return path

@pytest.fixture()
def mocked_worker(mocker):  # mocker is pytest-mock fixture
    mocker.patch('test_file.os.getcwd', return_value="Testing")

def test_work_on(mocked_worker):
    worker = Worker()  # here we create instance of Worker, not mock itself!!
    ans = worker.work_on()
    assert ans == "Testing"
Run Code Online (Sandbox Code Playgroud)

使用的库供参考:

pytest==5.3.0
pytest-mock==1.12.1

Run Code Online (Sandbox Code Playgroud)

  • 第一件事 - 可能是一个很好的理由。更大的范围可能会让你不喜欢的函数被嘲笑(这些是比你有很多测试要处理的可怕的错误)第二件事 - 你可以导入 mokcer 函数,然后创建你自己的函数具有所需范围的固定装置:`import pytest;from pytest_mock.plugin import _mocker;your_mocker = pytest.fixture(scope="module")(_mocker)` ps [pytest源代码](https://github.com/pytest -dev/pytest-mock/blob/main/src/pytest_mock/plugin.py) (2认同)