Python 模拟通信
我正在用python构建一个应用程序,它使用一个执行硬件通信的库的包装 我想创建一些测试单元,我对单元测试还很陌生,所以我想模拟通信,但我真的不知道怎么做 快速示例: 这是使用comm lib的应用程序代码Python 模拟通信,python,unit-testing,Python,Unit Testing,我正在用python构建一个应用程序,它使用一个执行硬件通信的库的包装 我想创建一些测试单元,我对单元测试还很陌生,所以我想模拟通信,但我真的不知道怎么做 快速示例: 这是使用comm lib的应用程序代码 def changeValue(id, val): current_value = comm.getval(id) if (current_value != val): comm.send(id, val) 我想在不执行通信的情况下对此进行测试,即用某个模拟
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):
....
....
诀窍是不要使用全局对象,如
comm
。如果可以,使调用方将comm
注入到类或方法中。然后,您要做的是在测试时通过模拟的comm
,然后在生产中通过真实的
因此,要么在类中创建一个comm
引用一个字段(并通过构造函数或setter方法将其注入),如下所示
或者在使用它的方法中将其作为参数,如下所示
def changeValue(id, val, myComm):
current_value = myComm.getval(id)
if (current_value != val):
myComm.send(id, val)
使用全局性的任何东西都会让模仿成为一种巨大的痛苦,试着在需要模仿的时候使用它
这是关于DI的另一篇好文章。它在java中,但在python中应该是相同的,您可以使用框架来完成这类工作。首先,你使用
comm=comm()。在这些情况下,您需要在MyClass
的模块中修补Comm
引用,以激活修补程序
因此,关于如何在不进行任何连接的情况下测试代码的示例可以是:
@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)
现在我可以开始解释我的答案的所有细节,比如为什么要使用or,但这意味着要重写大量的mock
文档和一系列答案。所以我希望这足够作为起点。什么是comm
?某个静态库或对象?comm是一个来自外部模块的python对象,我不想在测试中讨论它。我想做的是模拟那个对象,但我不知道怎么做,在检查我的答案之前我从来没有使用过模型(我添加了一个答案,这样截取的代码可以格式化)!我认为最好将代码片段放在问题本身中。其他人可以看到完整的类。但无论如何,我的观点仍然站得住脚。不是初始化comm=comm()
,而是在构造函数中接收comm
(我猜是python中的\uuuuuu init\uuuu
)。这样,在测试时,您将注入一个模拟的commI,它编辑了答案,以显示在类中注入comm
的情况,而不是在changeValue
中将其作为参数传递
@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)