TLDR:使用错误的参数顺序调用上游函数。我如何确保测试能够捕获到这一点?
这是我的设置的一个最小示例:
# functions.py
def inner(age, name):
if age > 18:
return f'{name} is an adult.'
else:
return f'{name} is a child.'
def outer(name, age):
info = inner(name, age)
return f'This is {name}. {info}'
# tests.py
from functions import inner, outer
from unittest.mock import Mock, patch
def test_inner():
name, age = "John", 43
info = inner(age, name)
expected = "John is an adult."
assert info == expected
def test_outer():
name, age = "John", 43
mock_get_info = Mock()
mock_get_info.return_value = "Info"
patch_get_info = patch("functions.inner", new=mock_get_info)
with patch_get_info:
info = outer(name, age)
expected = 'This is John. Info'
assert info == expected
mock_get_info.assert_called_once_with(name, age)
功能:
- 两个函数及其相应的测试。
inner
函数生成一个字符串,由test_inner
函数检查该字符串的正确性。outer
函数调用inner
函数并将其连接到它自己的字符串。test_outer
函数检查正确的串联和inner
函数调用。- 此外,除了这个最小的示例之外,
inner
函数可能会生成一个非常大的字符串,我不想在test_outer
中显式检查该字符串,这就是为什么内部
返回值被模拟。
您可能已经注意到,outer
函数实际上以错误的方式将参数传递给 inner
函数。这是因为我本可以决定更改 inner
函数的参数顺序并相应地更改 test_inner
,但忘记了 outer
函数调用 inner
函数。这不会被 test_outer
捕获,因为它是内部一致的。我们只在生产中发现内部
函数抛出错误。
如何确保下游函数的所有测试都能捕获修改后的函数定义?
最佳答案
我认为你走在正确的道路上。我相信您的测试没有捕获它,因为您断言了错误的顺序。
mock_get_info.assert_used_once_with(name,age)
应该是:
mock_get_info.assert_used_once_with(age, name)
来匹配 inner(age, name)
签名。
尽管如此,我认为更可靠的方法是使用关键字参数,然后断言调用参数是预期的字典。
例如:
# functions.py
def outer(name, age):
info = inner(age=age, name=name)
return f'This is {name}. {info}'
# tests
def test_outer():
name, age = "John", 43
mock_get_info = Mock()
mock_get_info.return_value = "Info"
patch_get_info = patch("functions.inner", new=mock_get_info)
with patch_get_info:
info = outer(name, age)
expected = 'This is John. Info'
assert info == expected
_, actual_kwargs = mock_get_info.call_args
assert actual_kwargs == {'name': name, 'age': age}
如果您想更严格,可以使用 *
[1] 强制 inner
仅接受关键字参数。但这也意味着您必须提供默认值,这根据您的用例可能没有意义。
示例:
def inner(*, age=0, name='default'):
if age > 18:
return f'{name} is an adult.'
else:
return f'{name} is a child.'
如果有人在不使用关键字参数的情况下调用它,Python 将在运行时引发异常。
Traceback (most recent call last):
File "/home/user/projects/so-test/functions.py", line 14, in <module>
outer('user', 32)
File "/home/user/projects/so-test/functions.py", line 9, in outer
info = inner(age, name)
TypeError: inner() takes 0 positional arguments but 2 were given
在我看来,inner(age=name, name=age)
比 inner(age, name)
更难犯这样的错误。
关于Python测试: How to test correct function calls of downstream functions?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69130033/