python 你能在pytest fixture中模拟系统功能吗?

wbrvyc0a  于 2023-03-28  发布在  Python
关注(0)|答案(1)|浏览(164)

我有下面的类,它做了一堆系统级的事情,比如调用os.systemmkdir并发出HTTP请求:

# mymodule.scene.py
import os
from pathlib import Path
import requests

class Scene:
    def __init__(self, id):
        self.do_stuff_1(id)
        self.do_stuff_2(id)

    def do_stuff_1(self, id):
        path = Path(f'/fake/cache/folder/{id}')
        path.mkdir(exist_ok=True)
        os.system(f'gsutil cp gs://myfile.txt /fake/cache/folder/{id}/myfile.txt')

    def do_stuff_2(self, id):
        resp = requests.get(f'http://www.google.com/{id}').json()
        return resp['status'] == 'OK'

我想创建一个pytest.fixture,它注入这个类,同时模拟所有的ospathlibrequests调用:

#tests/conftest.py
@pytest.fixture
def scene(mocker):
    # mocker.patch.object( ..
    # How do I mock Path, mkdir and os.system in the fixture
    scene = Scene()
    return scene

所以我可以如下测试它们:

# tests/test_scene.py
def test_do_stuff_1(scene):
    scene.do_stuff_1(123)
    # ? How do I assert Path, mkdir and os.system were called

def test_do_stuff_2(scene):
    scene.do_stuff_2(456)
    # ? How do I assert requests get as called

我的问题是如何在fixture中进行模拟,然后在测试中访问模拟的方法,以确认它们是用正确的参数调用的,并模拟返回值?

ngynwnxp

ngynwnxp1#

所以,从评论中我了解到,你有很多测试都需要模拟一些属性,也需要在fixture中构建场景。你有时需要检查一些被调用方法的模拟,但不是在所有测试中,也不是所有方法。
假设我理解正确,我会为你需要检查的模拟制作单独的夹具,这样你就可以在需要的时候访问它们,然后从它们“派生”场景,例如像这样的东西(在我的脑海中):

@pytest.fixture
def mocked_request(mocker):
    mocked = mocker.patch.object(...)
    yield mocked

@pytest.fixture
def mocked_system(mocker):
    yield mocker.patch("os.system")

@pytest.fixture
def scene(mocked_request, mocked_system, ...)
   yield Scene()

def test_do_stuff_1(scene, mocked_system):
    scene.do_stuff_1(123)
    mocked_system.assert_called_with(...)

def test_do_stuff_2(scene, mocked_request):
    scene.do_stuff_2(456)
    mocked_request.assert_called_once()

这是在假设你只需要对场景进行修补的情况下。如果你需要独立于场景应用修补,你可以只将它们设置为autouse

@pytest.fixture(autouse=True)
def mocked_request(mocker):
    mocked = mocker.patch.object(...)
    yield mocked

@pytest.fixture(autouse=True)
def mocked_system(mocker):
    yield mocker.patch("os.system")

@pytest.fixture
def scene()
   ...

为了检查被调用的方法,您需要访问mock示例,所以您只使用一个fixture的方法将无法工作(除非您返回一个tuple或一个字典,其中包含来自fixture的所有mock,但这将不方便使用)。

相关问题