我正在python中构建一个应用程序,它使用对执行硬件通信的库的包装
我想创建一些测试单元,我对单元测试很新,所以我想嘲笑通信,但我真的不知道怎么做
快速示例:
这是使用comm lib的应用程序代码
def changeValue(id, val):
current_value = comm.getval(id)
if (current_value != val):
comm.send(id, val)
我想在不执行通信的情况下测试它,即用一些模拟值替换comm.getval返回,并将comm.send发送到模拟的comm类。
任何人都可以提示吗?
问题是comm是类中的对象
让我们说课程是这样的:
class myClass:
comm = Comm()
....
def __init__():
comm = comm.start()
def changeValue(id, val):
....
....
答案 0 :(得分:2)
您可以将mock
框架用于此类工作。首先你要用
comm = Comm()
中的MyClass
,这意味着您在from comm_module import Comm
的模块中有MyClass
之类的内容。在这些情况下,您需要修补Comm
模块中的MyClass
引用,以使您的补丁处于活动状态。
所以如何在不进行任何连接的情况下测试代码的示例可以是:
@patch("my_class.Comm", autospec=True)
def test_base(self, mock_comm_factory):
mock_comm = mock_comm_factory.return_value
MyClass()
mock_comm.start.assert_called_with()
@patch("my_class.Comm", autospec=True)
def test_changeValue(self, mock_comm_factory):
mock_comm = mock_comm_factory.return_value
mock_comm.getval.return_value = 13
MyClass().changeValue(33, 23)
mock_comm.getval.assert_called_with(33)
mock_comm.send.assert_called_with(33, 23)
mock_comm.reset_mock()
mock_comm.getval.return_value = 23
MyClass().changeValue(33, 23)
mock_comm.getval.assert_called_with(33)
self.assertFalse(mock_comm.send.called)
现在我可以开始解释我的答案的所有细节,例如为什么使用autospec=True
或how to apply patch to all methods,但这意味着要重写大量mock
文档和SO答案。所以我希望这已经足够作为起点。
答案 1 :(得分:1)
诀窍不是使用像comm
这样的全局对象。如果可以,请将其设置为comm
由调用者注入您的类或方法。那么你所做的就是在测试时传递一个模拟的comm
,然后在生产中传递一个真实的模拟comm
。
所以你要么在你的类中引用class myClass:
....
def __init__(myComm):
comm = myComm;
comm = comm.start()
def changeValue(id, val):
current_value = comm.getval(id)
if (current_value != val):
comm.send(id, val)
....
引用一个字段(并通过构造函数或setter方法注入它),就像这样
def changeValue(id, val, myComm):
current_value = myComm.getval(id)
if (current_value != val):
myComm.send(id, val)
或者你在使用它的方法中将它作为一个参数,就像这样
deferred.when
使用全局任何会让嘲讽变得非常痛苦,只要你需要嘲笑某事,就试着使用Dependency Injection。
这是关于DI的另一篇好文章。它在java中,但在python http://googletesting.blogspot.ca/2008/07/how-to-think-about-new-operator-with.html
中应该是相同的