包裹: 要包装的模拟对象的项目。如果包裹不是None 那么调用 Mock 会将调用传递给包装对象(返回真实结果)。
通过将其包装在 Mock 对象中,您可以使用任何 Mock 的断言函数来检查对 range 的调用,例如 assert_called 检查目标是否至少被调用一次。
如果根本不调用断言,断言就会失败:
# Here, `range` wasn't used at all.
def avg(L):
return sum(L) / len(L)
class TestAverage(unittest.TestCase):
# same as the code above
$ python -m unittest -v main.py
test_avg (main.TestAverage) ... FAIL
======================================================================
FAIL: test_avg (main.TestAverage)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/main.py", line 15, in test_avg
wrapped_patch.assert_called()
File "/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/python3.10/unittest/mock.py", line 888, in assert_called
raise AssertionError(msg)
AssertionError: Expected 'range' to have been called.
使用patch时最重要的是要准确知道where to patch。在这种情况下,您可以查看文档或使用__module__了解range的模块:
>>> 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
一个稍微令人困惑的解决方法是“中断”range 的测试,这样,如果函数是真的使用range,那么它将不再起作用:
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)
所以,如果 avg 偷偷调用但没有真正使用 range,那么 test_avg_is_really_using_range 现在会失败,因为即使 range 损坏,它仍然会产生正确的值:
$ python -m unittest -v main.py
test_avg (main.TestAverage) ... ok
test_avg_really_using_range (main.TestAverage) ... FAIL
======================================================================
FAIL: test_avg_really_using_range (main.TestAverage)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/main.py", line 19, in test_avg_really_using_range
self.assertNotEqual(avg(L), 40)
AssertionError: 40.0 == 40
最后,作为旁注,我在所有示例中都在这里使用assertEqual,因为返回值的测试不是重点,但请务必阅读断言可能的浮点值的正确方法,例如。 How to perform unittest for floating point outputs? - python