您能否轻松测试方法定义是否已更改,但对该方法的调用尚未更新(使用 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
。
我有以下两种方法(简化):
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
。