2015-05-25 4 views
3

Я строй приложения в Python, который использует оболочку для библиотеки, которая выполняет аппаратную связьMocking Communications

Я хотел бы создать несколько тестовых единица, и я довольно новый для модульных тестов, поэтому я хотел бы, чтобы дразнить коммуникации, но я действительно не знаю, как это сделать

быстрый пример:

это код приложения с использованием ретрансляционных LIB

def changeValue(id, val): 
    current_value = comm.getval(id) 
    if (current_value != val): 
     comm.send(id, val) 

Я хочу протестировать это, не выполняя связи, т. Е. Заменяя возврат comm.getval каким-либо посмеянным значением и отправляя comm.send в изделенный класс comm.

Может кто подскажет это?


Дело в том, что Прдч является объектом внутри класса

скажем класс, как это:

class myClass: 
    comm = Comm() 
    .... 
    def __init__(): 
     comm = comm.start() 

    def changeValue(id, val): 
     .... 

    .... 
+0

что такое 'comm'? некоторая статическая библиотека или объект? – Hilikus

+0

comm - объект python из внешнего модуля, и я не хочу его освещать на тестах. То, что я хотел сделать, это издеваться над этим объектом, но я не знаю, как это можно сделать, я никогда не использовал макеты до того, как – Killercode

ответ

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

Хитрость заключается в том, чтобы не использовать глобальные объекты, такие как 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) 

.... 

или вы сделаете это параметр в методе, где он используется, как так

def changeValue(id, val, myComm): 
current_value = myComm.getval(id) 
if (current_value != val): 
    myComm.send(id, val) 

Использование глобальной ничего делает насмешливый огромную боль, попробуйте использовать Dependency Injection всякий раз, когда вам нужно что-то издеваться.

Это еще один хороший пост о DI. Он находится в java, но он должен быть одинаковым в python. http://googletesting.blogspot.ca/2008/07/how-to-think-about-new-operator-with.html

+0

проверить мой ответ (я добавил ответ, чтобы отредактировать код можно отформатировать)! – Killercode

+0

Я думаю, что лучше, если вы поместите свой фрагмент кода в вопрос. для других может оказаться полезным увидеть полный класс. Но, в любом случае, мой вопрос все еще стоит. Вместо инициализации 'comm = Comm()', получите 'comm' в конструкторе (я думаю' __init__' в python). таким образом, при тестировании вы вводите макет comm – Hilikus

+0

. Я отредактировал ответ, чтобы показать случай ввода 'comm' в классе, а не передавать его как параметр в' changeValue' – Hilikus