Unit test vs. Functional test

Май 5, 2009

Принято считать, что программный код должен быть покрыт тестами, степень покрытия у всех разная требования к тестам тоже. Считается, что юнит-тесты — это инструмент для разработчика, с помощью которого он «поднимает» продакшн-код. Очевидно, что не для всякого кода требуются юнит-тесты, скажу даже так, что 100% процентное покрытие кода обходится очень дорого и совсем не означает, что система не содержит ошибок или обезопасена от них. Юнит-тестом принято считать тест, который быстр, прост, не манипулирует с другими системами (файловой, базой данных, …) Таким образом, чтобы писать юнит-тесты реальную систему надо чем-то подменять, но так ли это эффективно?

Надо заметить, что Питон позволяет очень элегантно мокировать объекты реальных систем, лично я предпочитаю пользоваться библиотекой Mock, с помощью которой можно замокировать любой объект любого модулю, сделать индирект-инпут в тестируемую функцию через мок-объект, проверить аргументы, с помощью которых вызывался мокируемый объект, возможности, в общем хорошие, при внешне элегантном виде самого теста. Для примера я бы хотел рассмотреть мой код, который считывает настройки с файла:
<pre>

#production

settings = {}

def load():
if not os.path.exists(path): return

f = codecs.open(path, 'r', 'utf_8')
try:
content = f.readlines()
for line in content:
key, value = line.split("=", 1)
settings[key] = value
finally:
f.close()

#test

@patch("production.settings.codecs", Mock())
def testLoad(self, key, value, convert):
sut.codecs.open.return_value = mockFile = Mock()
mockFile.readlines.return_value = ["key1=value1", "key2=1"]
sut.load()
self.assertEquals(sut.get("key1", None), "value1")

</pre>
Казалось бы все просто, но вот программа, которая таким образом считывает адрес блютус-устройства падает, даже не выдавая текст исключения, пришлось потратить около сорока минут прежде, чем я разобрался. В тесте я предполагаю, что при чтении файла строчки приходят именно в таком виде, как в коде теста (["key1=value1", "key2=1"]: тут используется мокирование и реальный файл подменяется объектом, которому назначается нужное поведение — в данном случаи реакция на получение его содержимого). Оказывается, что строчки приходят с символом \n в конце, и программа пыталась подключится к устройству по некорректному адресу и слетала. Можно ли было не тратить сорок мнут на поиск этого бага? Да, просто создавать реальный файл на файловой системе, наполнять его тестовыми данными и проверять правильность работы кода условиях более приближенных к реальным. Решение проблемы заняло 10 секунд — settings[key] = value.strip()

Я понимаю, что не все объекты можно подменить, но многие, есть легкие СУБД, http-сервера и прочее — чем ближе тестируемая система получается к реальной, тем более уверенности, что код будет работать именно так, как ожидается. Я думаю, каждый разработчик, использующий тесты именно как инструмент, помогающий ему в процессе написания кода, а не как какое-то требование свыше, рано или поздно приходит к выводу, что чистые юнит-тесты недостаточно эффективны в качестве такого помощника, однако, надо всегда следить за временем выполнения теста, так как медленные тесты только раздражают.

4 Comments to "Unit test vs. Functional test"

  1. Владимир wrote:

    Очень чудно :D :)

  2. кaмycя wrote:

    Прикольно, а продолжение будет?

  3. immigration whistleblower wrote:

    Ӏ simply could not leave your website prioг to sugfesting that
    I extremely enjoyed thе ᥙsսal info an individual suppl
    for youг guests? Is gonjna be back continuously to сhrck out new posts

  4. Alda wrote:

    What’s ᥙpp it’s me, I am also visitіng this weeb page on ɑ гegular basis,
    this web pageе is in fаct pleasant and the visitors are truly sharing pleasant thoughts.

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org