首页 > 解决方案 > 修补单元测试中的单个类方法并断言它被调用一次

问题描述

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

例如:

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函数只被调用一次?

标签: pythonpython-unittestpython-unittest.mock

解决方案


问题是你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()

推荐阅读