如何对 Python 函数内部进行的函数调用序列进行单元测试?

问题描述 投票:0回答:2

我想对一个函数进行单元测试,并断言函数工作流()内部进行的函数调用顺序是否正确。 比如,

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

我搜索了很多讨论,但从未找到一个回答我的问题。

python unit-testing assert
2个回答
6
投票

如果您使用

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()
方法
将您以不同方式创建的模拟附加到父级。


1
投票

在我看来,测试或特别是 TDD 的真正目的是拥有更好设计的代码。如果为你的代码编写测试变得困难,那么这意味着你的代码是高度耦合的,你需要重构它。此外,编写断言函数顺序的测试会使测试与代码过于耦合并且非常脆弱。

话虽如此,您可以以一种有点黑客的方式测试顺序。假设您有两个名为

func_a
func_b
的函数,并且您希望确保
func_a
func_b
之前调用。将
func_a
替换为返回一些随机值的模拟,以便它停止进一步执行。也模拟
func_b
,并确保调用
func_a
并且不调用
func_b
。您还需要对其他排列执行此操作。

© www.soinside.com 2019 - 2024. All rights reserved.