如何对函数内部进行的函数调用序列进行单元测试 [python]

How to unittest the sequence of function calls made insde a fuction [python]

我想对一个函数进行单元测试,并断言函数调用的顺序是否在函数 workflow() 内进行。 像,

      [1st called] fetch_yeargroup_ls()
      [2nd called] invoke_get_links()....... 

我搜索了许多讨论,但从未找到回答我问题的人。

在我看来,测试或特别是 TDD 的真正目的是设计更好的代码。如果为您的代码编写测试变得困难,则表明您的代码是高度耦合的,您需要对其进行重构。此外,编写断言函数顺序的测试会使测试与代码过于耦合并且非常脆弱。

话虽如此,您还是可以测试订单,虽然有点老套。比如说,您有两个名为 func_afunc_b 的函数,您希望确保 func_afunc_b 之前被调用。将 func_a 替换为 returns 一些随机值的模拟,以便它停止执行进一步发生。还要模拟 func_b,并确保调用 func_a 并且不调用 func_b。您也需要对其他排列执行此操作。

如果您正在使用 mock,您可以在修补这些函数时将模拟创建为父模拟的属性:

try:
    # Python 3
    from unittest.mock import MagicMock, patch, call
except ImportError:
    # Python 2, install from PyPI first
    from mock import MagicMock, patch, call
import unittest

from module_under_test import function_under_test

class TestCallOrder(unittest.TestCase):
    def test_call_order(self):
        source_mock = MagicMock()
        with patch('module_under_test.function1', source_mock.function1), \
                patch('module_under_test.function2', source_mock.function2), \
                patch('module_under_test.function3', source_mock.function3)

            # the test is successful if the 3 functions are called in this
            # specific order with these specific arguments:
            expected = [
                call.function1('foo'),
                call.function2('bar'),
                call.function3('baz')
            ]

            # run your code-under-test
            function_under_test()

            self.assertEqual(source_mock.mock_calls, expected)

因为这 3 个函数附加到 source_mock,所以对它们的所有调用都记录在 Mock.mock_calls 属性中的父模拟对象上,您可以对它们的调用顺序进行断言。

我只是通过在 source_mock 对象上查找它们作为属性来附加 3 个函数模拟,但您也可以使用 Mock.attach_mock() method 将您以不同方式创建的模拟附加到父对象.