【问题标题】:Patch a single class method in a unittest and assert it is called once修补单元测试中的单个类方法并断言它被调用一次
【发布时间】:2020-06-18 13:30:32
【问题描述】:

如何修补类中的方法,然后断言该修补方法仅被调用一次?

例如:

import typing
import unittest
import unittest.mock

class Example:
    def __init__(self: "Example") -> None:
        self._loaded : bool = False
        self._data : typing.Union[str,None] = None

    def data(self: "Example") -> str:
        if not self._loaded:
            self.load()
        return self._data

    def load(self: "Example") -> None:
        self._loaded = True
        # some expensive computations
        self._data = "real_data"

def mocked_load(self: "Example") -> None:
    # mock the side effects of load without the expensive computation.
    self._loaded = True
    self._data = "test_data"

class TestExample( unittest.TestCase ):
    def test_load(self: "TestExample") -> None:
        # tests for the expensive computations
        ...

    @unittest.mock.patch("__main__.Example.load", new=mocked_load)
    def test_data(
        self: "TestExample",
        # patched_mocked_load: unittest.mock.Mock
    ) -> None:
        example = Example()
        data1 = example.data()
        self.assertEqual(data1, "test_data")
        # example.load.assert_called_once()
        # Example.load.assert_called_once()
        # mocked_load.assert_called_once()
        # patched_mocked_load.assert_called_once()

        data2 = example.data()
        self.assertEqual(data2, "test_data")
        # Should still only have loaded once.
        # example.load.assert_called_once()
        # Example.load.assert_called_once()
        # mocked_load.assert_called_once()
        # patched_mocked_load.assert_called_once()

if __name__ == '__main__':
    unittest.main()

如何在test_data 单元测试中断言修补后的load 函数只被调用一次?

【问题讨论】:

    标签: python python-unittest python-unittest.mock


    【解决方案1】:

    问题是你用自己的函数替换了load,这不是一个模拟函数,因此没有assert_called_xxx 方法。
    您需要将其替换为模拟并将所需的行为添加到模拟中:

        @unittest.mock.patch("__main__.Example.load")
        def test_data(
                self: "TestExample",
                patched_mocked_load: unittest.mock.Mock
        ) -> None:
            example = Example()
            patched_mocked_load.side_effect = lambda: mocked_load(example)
            data1 = example.data()
            self.assertEqual(data1, "test_data")
            patched_mocked_load.assert_called_once()
    
            data2 = example.data()
            self.assertEqual(data2, "test_data")
            patched_mocked_load.assert_called_once()
    

    【讨论】:

    • 这行得通,但感觉就像在将类实例直接传递给副作用 lambda 时必须使用变通方法,如果有两个实例,这将不是一个可行的解决方案测试中的 Example 类作为 selfmocked_load 函数中引用的实例是有效的硬编码,而不是通过调用动态传递。
    • 同意,我也不喜欢它,但想不出更好的东西……可能遗漏了什么。
    猜你喜欢
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多