Python 模拟通信

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) 我想在不执行通信的情况下对此进行测试,即用某个模拟

我正在用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):
        ....

    ....

诀窍是不要使用全局对象,如
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)