import builtins
import unittest
from unittest.mock import patch
# I don't know what L is supposed to be, and I know that there
# are better ways to compute average of a list, but the code
# for calculating the average is not important for this question.
def avg(L):
total = 0
for index in range(len(L)):
total += L[index]
return total / len(L)
class TestAverage(unittest.TestCase):
def test_avg(self):
with patch("builtins.range", wraps=builtins.range) as wrapped_patch:
expected = 47
actual = avg([1,49,91])
self.assertEqual(expected, actual)
wrapped_patch.assert_called()
if __name__ == '__main__':
unittest.main()
$ python -m unittest -v main.py
test_avg (main.TestAverage) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
>>> range
<class 'range'>
>>> range.__module__
'builtins'
但是这个测试有点幼稚,因为即使avg没有真正使用range,它仍然可以通过:
def avg(L):
range(len(L)) # Called but really unused. Sneaky!
return sum(L) / len(L)
class TestAverage(unittest.TestCase):
# same as the code above
$ python -m unittest -v main.py
test_avg (main.TestAverage) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
def avg(L):
range(len(L)) # Called but really unused. Sneaky!
return sum(L) / len(L)
class TestAverage(unittest.TestCase):
def test_avg(self):
# same as above
def test_avg_is_really_using_range(self):
L = [10,20,90]
# Is it returning the correct result?
self.assertEqual(avg(L), 40)
# OK, but did it really use `range`?
# Let's try breaking `range` so it always yields 0,
# so we expect the return value to be *different*
with patch("builtins.range", return_value=[0,0,0]):
self.assertNotEqual(avg(L), 40)
1条答案
按热度按时间zhte4eai1#
您可以使用Python的
unittest.mock
模块 Packagebuiltins
模块中的range
函数,然后让测试Assert Package 后的range
确实被调用了。例如,使用Python的
unittest
框架编写测试:它使用
unittest.mock
的patch
作为builtins.range
函数的目标,通常情况下,patch
用于替换目标的行为和/或返回值,但在本例中,您可以传递wraps=builtins.range
(它被传递给底层的Mock
对象),这意味着"* 我只想监视调用,但不修改其行为 *":None
,则调用模拟将把调用传递给 Package 的对象(返回实际结果)。通过将其 Package 在
Mock
对象中,您可以使用Mock
的任何assert函数来检查对range
的调用,例如assert_called
,它检查目标是否至少被调用过一次。您可以通过Assertrange
被调用的次数来更具体地说明:如果根本不调用Assert,则Assert将失败:
一个三个三个一个
在使用
patch
时最重要的是知道在哪里打补丁,在这种情况下,你可以查看文档或者使用__module__
来知道range
的模块:但是这个测试有点幼稚,因为即使
avg
没有真正使用range
,它仍然可以通过:一个稍微令人困惑的解决方案是"破坏"
range
的测试,这样,如果函数 * 真的 * 使用range
,那么它将不再工作:因此,如果
avg
正在偷偷调用,但实际上并没有使用range
,那么test_avg_is_really_using_range
现在将失败,因为即使range
已损坏,avg
仍然会产生正确的值:最后,作为附带说明,我在所有示例中使用
assertEqual
,因为对返回值的测试不是重点,但请务必阅读Assert可能的浮点值的正确方法,例如How to perform unittest for floating point outputs? - python