在 class 方法中模拟第三方函数

Mocking third-party function inside class method

这可能是一个小问题,但我找不到合适的解决方案,而且我不明白如何解决它。我简化了问题,所以我有两个文件 my_module.pytest_module.py 在同一本地化。

import numpy as _np


class MyClass:

    def __init__(self) -> None:
        self.attribute = 1
        self.method()

    def method(self) -> None:
        arr = _np.arange(9).reshape(-1, 3)
        self.attribute = 2
from unittest.mock import Mock, patch

import pytest

from my_module import MyClass


@pytest.fixture
def init_mock():
    with patch.object(MyClass, '__init__', return_value=None) as init:
        yield init


@pytest.fixture
def method_mock():
    with patch.object(MyClass, 'method') as method:
        yield method


@pytest.fixture
def my_class_init_mock(init_mock):
    yield MyClass()


@pytest.fixture
def my_class_method_mock(method_mock):
    yield MyClass()


def test_init(my_class_method_mock):
    assert my_class_method_mock.attribute == 1


def test_method(my_class_init_mock):
    my_class_init_mock.method()
    assert my_class_init_mock.attribute == 2

两项测试全部通过。此外,我需要检查 _np.arange(9).reshape 是否使用 -1, 3 参数调用过一次。我发现我应该从my_module.py直接引用numpy。我试图在上次测试上方添加 @patch('my_module._np') 。我还尝试将模块的fixture传递给my_class_method_mock的fixture。不幸的是,当我触发 .method() 函数时,我无法调用这个模拟。如何在它们之间建立联系?

这可以通过定义 _np 的夹具并检查是否调用了此模拟来实现:

@pytest.fixture
def numpy_mock():
    with patch('my_module._np') as numpy:
        yield numpy

...

def test_method(my_class_init_mock, numpy_mock):
    my_class_init_mock.method()
    numpy_mock.arange.assert_called_once_with(9)
    numpy_mock.arange().reshape.assert_called_once_with(-1, 3)
    assert my_class_init_mock.attribute == 2

请注意,我们可以断言方法链接的每一部分。