pytest如何在类的__init__中模拟函数调用

3

我有一个像这样的类:

from external_package.module.sub_module import fun

class MyClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.z = fun()
        
    def printer(self):
        print(f"X : {self.x}, y : {self.y}, z: {self.z}")

我想为这个类编写一个单元测试,并模拟在init方法中发生的函数调用。

我尝试过像这样打补丁,

from external_package.module import sub_module
    
def test_my_class(mocker):

    mocker.patch.object(sub_module, 'fun', return_value="this is mocked")
    obj = MyClass(10, 20)
    
    assert obj.z == "this is mocked"

但是我可以看到该调用没有被打补丁,而是在init方法中发生了函数调用。

我该如何使用pytest-mock或其他模拟包来打补丁呢?

2个回答

2

您应该使用函数被使用的路径而不是其原始路径或位置来模拟函数。在下面的示例中,定义了对象MyClass中fun方法将被模拟,并返回值为“this is mocked”。

from external_package.module import sub_module
from my_class import MyClass

def test_my_class(mocker):

    mocker.patch.object(MyClass.submodule, 'fun', return_value="this is mocked")
    obj = MyClass(10, 20)
    
    assert obj.z == "this is mocked"

查看这个链接,了解如何在Python中模拟对象的一些好例子。


这里出现了错误:MyClass没有名为fun的属性。 - Sreeram TP
我忘记在 MyClass 后面添加 sub_module,但已经更新了。对于这个错误感到抱歉。 - daniboy000

0

我通过在源代码中稍微更改导入语句来解决了这个问题。

from external_package.module import sub_module 

class MyClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.z = sub_module.fun()
        
    def printer(self):
        print(f"X : {self.x}, y : {self.y}, z: {self.z}")

请注意,我正在导入子模块并从导入的子模块调用方法。
现在,在测试中,我像这样使用了pytest-mock fixture,
import external_package
    
def test_my_class(mocker):

    method = mocker.patch("external_package.module.sub_module.fun")
    method.return_value = "this is mocked"

    obj = MyClass(10, 20)
    
    assert obj.z == "this is mocked"

我不确定为什么这个方法有效而之前的方法无效。希望有人能够澄清一下。


1
在你的第二个实现中,你非常明确地指定了应该模拟哪个函数,你定义了当在external_package内执行时,来自sub_module的函数fun被模拟并且必须返回"this is mocked"。在你的第一个实现中,你模拟了sub_module,但没有指定它应该在哪里被模拟。 - daniboy000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接