我认为单元测试在开发过程中是必须存在的,也是每个程序员必须做的事情。曾经我也疑惑过为什么要写单元测试用例,后来发现那是因为,那个时候是为了写测试用例而写,而非是为了验证自己的产品代码的内部逻辑而写。再加上对自己写的产品代码过于自信,总认为自己在设计代码逻辑的时候已经反复思考过,那再去写一个测试用例去做自己做过的事情的意义在哪?意义就在于:
你的单元测试用例可以保护你的代码不被后合入的代码破坏。
说白了,你就是个人,始终无法像机器一样,无法保证你每时每刻都能不出疏漏。
随着代码库越来越庞大,在写单元测试的时候经常会碰到一些瓶颈,单元测试越来越慢。比如如何模拟一些外部的库的调用,如何模拟数据库返回数据,如何减少一些IO访问来提升单元测试的速度?这就是Python开发unittest.mock库的原因,它可以减少依赖关系和模拟一些异常效果,还可以在执行动作后,断言使用了哪些方法/属性以及调用它们的参数。
1. Mock类
unittest.mock最核心的部分就是Mock类。这个类可以创建一个Mock实例,然后可以让这个实例具有一些属性和方法,我们可以:
直接给属性赋值
configure_mock
或者使用Mock类的参数去初始化实例
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.return_value = 3
>>> m.foo = 42
>>> m.configure_mock(bar='baz')
>>>
>>> m()
3
>>> m.foo
42
>>> m.bar
'baz'
如果需要对一个mock实例的调用返回特定值,需要使用return_value这个属性,
m.return_value = 42
也可以直接在初始化mock实例的时候,把这个参数值带上
m = Mock(return_value=42)
side_effect参数在Mock里非常实用,它可以模拟一些负面效果,比如异常,每次调用返回不同值。
如果side_effect是iterable,那么每次对mock对象调用都会返回iterable的下一个值。
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'
>>> try:
m()
except StopIteration:
assert True
else:
assert False
如果side_effect是一个异常:
>>> m.side_effect = KeyError(&#