Python中如何测试被Mock类的实例化情况?
问题描述
需要为bar模块的Bar类编写无外部依赖的单元测试,所有依赖通过Mock实现。当Bar传入参数7时,会实例化foo.Foo作为成员,但测试不想导入foo或foo.Foo。当前Mock配置后,调用mock_foo.assert_called()验证失败,报错“Expected 'mock' to have been called.”。
问题原因
你Mock的层级错了。bar模块里调用的是foo.Foo(即foo模块下的Foo类),但你只替换了bar.foo这个模块对象,并没有替换bar.foo.Foo这个类引用。bar在导入时已经加载了原foo模块,替换bar.foo不会自动修改它内部的Foo属性,所以实际调用的还是原foo.Foo,你的Mock根本没被触发。
解决方案
下面是两种正确的实现方式:
方法一:直接替换bar.foo.Foo为Mock对象
直接把bar模块里的foo.Foo替换成Mock类,这样Bar实例化时调用foo.Foo(7)就会触发这个Mock。
修改后的测试代码:
#!/usr/bin/env python3 import unittest from unittest import mock import bar class MyTest(unittest.TestCase): def test_bar(self): # 替换bar模块内的foo.Foo为Mock类 mock_foo_class = mock.Mock() bar.foo.Foo = mock_foo_class b = bar.Bar(7) # 验证Foo类被调用一次,传入参数7 mock_foo_class.assert_called_once_with(7) # 验证b.y是Mock实例化后的对象 self.assertIsInstance(b.y, mock.Mock) def test_int(self): b = bar.Bar(8) self.assertIsInstance(b.y, int) if __name__ == '__main__': unittest.main()
方法二:使用unittest.mock.patch装饰器(更规范)
用patch直接拦截bar.foo.Foo,测试结束后自动恢复原引用,避免污染其他测试用例,写法更简洁。
修改后的测试代码:
#!/usr/bin/env python3 import unittest from unittest import mock import bar class MyTest(unittest.TestCase): @mock.patch('bar.foo.Foo') def test_bar(self, mock_foo_class): b = bar.Bar(7) # 验证Foo类被调用一次,参数为7 mock_foo_class.assert_called_once_with(7) self.assertIsInstance(b.y, mock.Mock) def test_int(self): b = bar.Bar(8) self.assertIsInstance(b.y, int) if __name__ == '__main__': unittest.main()
内容的提问来源于stack exchange,提问作者buhtz
相关产品推荐
相关产品推荐

