我想对一个函数进行单元测试,并断言函数工作流()内部进行的函数调用顺序是否正确。 比如,
[1st called] fetch_yeargroup_ls()
[2nd called] invoke_get_links().......
我搜索了很多讨论,但从未找到一个回答我的问题。
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()
方法 将您以不同方式创建的模拟附加到父级。
在我看来,测试或特别是 TDD 的真正目的是拥有更好设计的代码。如果为你的代码编写测试变得困难,那么这意味着你的代码是高度耦合的,你需要重构它。此外,编写断言函数顺序的测试会使测试与代码过于耦合并且非常脆弱。
话虽如此,您可以以一种有点黑客的方式测试顺序。假设您有两个名为
func_a
和 func_b
的函数,并且您希望确保 func_a
在 func_b
之前调用。将 func_a
替换为返回一些随机值的模拟,以便它停止进一步执行。也模拟 func_b
,并确保调用 func_a
并且不调用 func_b
。您还需要对其他排列执行此操作。