如何正确地模拟实例化类变量的函数?

2024-06-23 03:00:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我的源文件中有类似的内容

# code.py

def some_func():
    # doing some connections and stuff
    return {'someKey': 'someVal'}


class ClassToTest:

    var = some_func()

我的测试文件看起来像这样。。。我试图模拟some_func,因为我想避免创建连接

# test_code.py

from src.code import ClassToTest


def mock_function():
    return {"someOtherKey": "someOtherValue"}


class Test_Code(unittest.TestCase):

    @mock.patch('src.code.some_func', new=mock_function)
    def test_ClassToTest(self):
        self.assertEqual(ClassToTest.var, {"someOtherKey": "someOtherValue"})

但这不起作用。另一方面,如果var是一个即时变量,mock可以正常工作。我猜这是由于类变量在导入过程中被初始化。在var被初始化之前,我如何正确地模拟some_func


Tags: pytestsrcreturnvardefcodefunction
1条回答
网友
1楼 · 发布于 2024-06-23 03:00:20

导入code.py时,还没有激活的修补程序,因此ClassToTest.var初始化时,它使用原始的some_func。只有到那时src.code.some_func的补丁才会生效,现在显然为时已晚

解决方案1

您可以做的是修补some_func,然后重新加载code.py,以便它重新初始化ClassToTest,包括其属性var。因此,由于我们在重新加载code.py时已经有了一个活动补丁,那么ClassToTest.var将被设置为补丁值

  • 但是,如果类和补丁函数都存在于同一个文件中,我们就不能这样做,因此要使其可测试,请将some_func移动到另一个文件,然后导入它

src/code.py

from src.other import some_func


class ClassToTest:
    var = some_func()

src/other.py

def some_func():
    # doing some connections and stuff
    return {'realKey': 'realValue'}

测试代码.py

from importlib import reload
import sys
import unittest
from unittest import mock

from src.code import ClassToTest  # This will always refer to the unpatched version


def mock_function():
    return {"someOtherKey": "someOtherValue"}


class Test_Code(unittest.TestCase):
    def test_real_first(self):
        self.assertEqual(ClassToTest.var, {"realKey": "realValue"})

    @mock.patch('src.other.some_func', new=mock_function)
    def test_mock_then_reload(self):
        # Option 1:
        # import src
        # reload(src.code)

        # Option 2
        reload(sys.modules['src.code'])

        from src.code import ClassToTest  # This will be the patched version
        self.assertEqual(ClassToTest.var, {"someOtherKey": "someOtherValue"})

    def test_real_last(self):
        self.assertEqual(ClassToTest.var, {"realKey": "realValue"})

输出

$ pytest -q 
...                                                                                           [100%]
3 passed in 0.04s

解决方案2

如果您不希望在测试期间调用真正的some_func,那么仅仅重新加载是不够的。需要做的是永远不要导入包含ClassToTest的文件,也不要导入任何会间接导入它的文件。仅在some_func的活动修补程序已建立后导入它

from importlib import reload
import sys
import unittest
from unittest import mock

# from src.code import ClassToTest  # Remove this import!!!


def mock_function():
    return {"someOtherKey": "someOtherValue"}


class Test_Code(unittest.TestCase):
    @mock.patch('src.other.some_func', new=mock_function)
    def test_mock_then_reload(self):
        from src.code import ClassToTest  # Move the import here once the patch has taken effect already
        self.assertEqual(ClassToTest.var, {"someOtherKey": "someOtherValue"})

相关问题 更多 >

    热门问题