您能否轻松测试方法定义是否已更改,但对该方法的调用尚未更新(使用 Pytest 和 Mock)?

Can you easily test whether a method definition has changed, but a call to the method has not been updated (with Pytest and Mock)?

我有以下两种方法(简化):

def func_a(u, v, w, x, y, z):
    ##Do some irrelevant stuff
    newVariable = func_b(u, v, w, y)
    ##Do some more irrelevant stuff

def func_b(u, v, w, y):
    ##Do some manipulation of the variables
    ##Call some more methods, like func_c, func_d, func_e
    newVariable = 1 #In reality; some value that is calculated
    return newVariable 

func_a相当简单,但是func_b根据一些条件调用了几个不同的方法,这里不相关。此功能在未来很可能会发生变化,因为它的特点是计算可能会在项目的后期阶段发生变化。我的问题如下:

有了Pytest和Mock,我们可以轻松测试func_a的功能;你可以模拟 func_b 并设置 return_value.

检查func_b是否从func_a调用正确也很容易;使用 assert_called_with 我们可以确保在调用函数时使用预期值,如下所示:

@patch('func_b') 
def test_func_a_calls_func_b_correctly(b_mock):
    func_a(1,2,3,4,5,6)
    b_mock.assert_called_with(1, 2, 3, 5)

然而,如果我们改变 func_b 的定义(例如:func_b(u, v, w, y, q),这个测试仍然会通过,因为 func_a 中的调用仍然是“预期的” 。这当然不是我们想要的,因为测试会通过,但是程序会崩溃运行。有没有办法通过这种方式测试方法定义的变化?

如果没有,那么最好的测试是不是模拟 func_b,而是模拟在 [= 中调用的 func_c、func_d 和 func_e 26=]?这当然可以正常工作,但对于单元测试来说似乎不太干净。

这是一个哲学问题 - mock 并非旨在模拟它正在替换的功能,只是提供一个虚假的输入和输出以查看它是如何被调用的。

如果您确实需要确保您的代码对函数的调用仍然 'match' 函数的行为,那么您必须将原始函数与 mock(或call) 在测试的时候。

例如,在您当前的示例中,您可以这样做:

from inspect import signature

@patch('func_b') 
def test_func_a_calls_func_b_correctly(b_mock):
    func_a(1,2,3,4,5,6)

    # Check that the number of params passed when calling func_b
    # is the same as the number of parameters that the 'real' func_b expects
    assert len(mock.call_args.args) == len(signature(func_b).parameters)

但是,这不能防止参数更改的顺序或 'purpose',这需要进一步检查 func_b