Добрый день.
Модуль MiniMock – пожалуй, один из наиболее изящных способов создания mock-объектов в Python. История MiniMock началась с 25 строк кода, которые Ian Bicking набросал под впечатлением от модуля python-mock. Будучи приверженцем doctest, Ian решил задействовать его возможности для подготовки имитаторов. В результате, по наводке python-mock и с doctest наперевес, появился MiniMock, возможности которого охватывают базовые сценарии создания mock-объектов. За три года усилиями энтузиастов функциональность модуля MiniMock значительно расширилась, но он по-прежнему остается компактным и удобным в использовании.
Текущая версия модуля доступна на python.org. Ниже представлена работа с последней на сегодня версией 1.2.3. В качестве примера рассматривается максимально упрощенная система выдачи книг в библиотеке. Модуль library.py содержит два класса Books и Readers. Работа с классами Books и Readers иллюстрируется функцией simple_example. Файл library.py:
class Books: def __init__ (self, title): self.title = title self.reader = "In place" def current_reader (self, reader): self.reader = reader def get_reader (self): return self.reader class Readers: def __init__ (self, name): self.name = name self.book = "" def current_book (self, book): self.book = book def get_book (self): return self.book def simple_example(): reader = Readers ("Obama") book = Books ("War and Peace") reader.current_book (book.title) book.current_reader (reader.name) title = reader.get_book() print title reader_name = book.get_reader() print reader_name if __name__ == "__main__": simple_example()
Запуск:
[capt@rh564 Work]# python library.py War and Peace Obama
Когда книга выдается читателю, должны быть выполнены два действия: название книги необходимо записать в формуляр читателя, а фамилию читателя – в формуляр книги. Этим занимается функция book_checkout, представленная в модуле main.py:
from library import Readers, Books def book_checkout (reader, book): reader.current_book (book.title) book.current_reader (reader.name)
Подготовим тест для этой функции. Мы хотим быть уверенными в том, что при ее выполнении будут вызваны два метода: current_book для читателя и current_reader для книги. Дополним скрипт main.py:
from minimock import Mock, TraceTracker, assert_same_trace from library import Readers, Books def book_checkout (reader, book): reader.current_book (book.title) book.current_reader (reader.name) def test_book_checkout(): tt = TraceTracker() Readers.current_book = Mock ('Readers.current_book', tracker = tt) Books.current_reader = Mock ('Books.current_reader', tracker = tt) reader = Readers("Obama") book = Books("War and Peace") expect_mock_output = """\ Called Readers.current_book('War and Peace') Called Books.current_reader('Obama')""" book_checkout (reader, book) assert_same_trace(tt, expect_mock_output) test_book_checkout()
Результат запуска main.py более чем лаконичен:
[capt@rh564 Work]# python main.py [capt@rh564 Work]#
Что произойдет, если мы изменим логику работы book_checkout? Скажем, уберем вызов book.current_reader (reader.name) и тем самым “забудем” прописать в формуляре книги ее нынешнего читателя? Вот что получится:
[capt@rh564 MiniMock]# python main.py Traceback (most recent call last): File "main.py", line 25, in ? test_book_checkout() File "main.py", line 23, in test_book_checkout assert_same_trace(tt, expect_mock_output) File "build/bdist.linux-x86_64/egg/minimock.py", line 213, in assert_same_trace AssertionError: Expected: Called Readers.current_book('War and Peace') Called Books.current_reader('Obama') Got: Called Books.current_reader('Obama')
Причина появления AssertionError: при выполнении book_checkout вызов методов отличается от ожидаемого. Таким образом, unit-тест test_book_checkout отслеживает поведение функции book_checkout. Если логика ее работы изменится, мы будем предупреждены.
Более подробную информацию о MiniMock можно получить в документации к модулю. Помимо этого, будет полезно ознакомиться с кодом minimock.py (доступен в архиве MiniMock-1.2.3.tar.gz). Он небольшой, но достаточно информативный. Каждый класс снабжен описанием и примерами его использования. Счастливого взлета.
Что такое качество программного обеспечения и как его улучшить: теория и практика, задачи и решения, подводные камни и обходные пути.
Автор комментария : Ochir | June 22, 2009
Добрый день!
спасибо за статью, пригодилась.
А вы пробовали использовать другие mock модули?
в частности mox и pmock?
С уважением,
Очир
[Ответить]
Автор комментария : Капитан Аляска | June 23, 2009
Добрый день, Очир! Спасибо за добрые слова. Pmock не пробовал (вот что о нем пишут: pMock has not been under active development since mid 2004). В Mox смотрел только примеры из документации. Задач, в которых было бы удобно его применить, пока не встретил.
[Ответить]
Автор комментария : Очир | July 13, 2009
можете удалить предыдущий коммент. Проблема была в классе, в котором находились тест кейсы. При вынесении тест кейсов в отдельные функции заработало. Правда почему не работает в классах - загадка…
[Ответить]
Автор комментария : Капитан Аляска | July 14, 2009
Добрый день, Очир. restore() пробовал, работает. Но не вызывал из tearDown(). Посмотрите вот эту ссылку: похоже, решалась подобная задача:
http://osdir.com/ml/python.testing.general/2008-02/msg00000.html
[Ответить]