Tuesday, February 10, 2009

TDD и покрытие кода тестами

Написал развернутый комментарий на тему "Юнит тесты и TDD" в блог bishop-it.ru, после чего он благополучно обрезался и половина пропала - наверное сработало ограничение на размер. Полный комментарий публику здесь.

Я решил завести отдельный ярлычок "Комментарии" для таких постов, думаю их будет больше одного.

--- Cut ---

Что значит 100% покрытие кода тестами? :)

На первой лекции по тестированию нам привели пример программы из 10 строк кода с двумя вложенными циклами и показали, что чтобы полностью проверить работу этого кода нужно выполнить 10^18 операций :) Я думаю тестировщики знают про это.

TDD - это вовсе не о тестировании и не о покрытии кода тестами. Я вообще не понимаю откуда возникла цифра 100% - я много читал/смотрел/использовал TDD, но никогда не слышал о связи TDD и покрытии кода тестами.

Соглашусь с Андреем Валяевым, что TDD - это подход к разработке, который позволяет разработчикам (а не тестировщикам) облегчить жизнь. И именно по этой же причине, если я правильно понимаю, TDD нравится автору поста.

TDD != тестирование.

Тем более тестирование GUI (и все что касается GUI вообще), которое я вообще считаю шаманством и даже не пытаюсь туда лезть :) Единственное, что я могу понять в тестировании GUI и действительно использую - это ручное тестирование (отредактировать, запустить, проверить UI). Я могу это делать сам (и делаю) или могу отдать специально обученному человеку (и отдаю), который проверяет работу системы по заранее написанным сценариям, составленным по ТЗ.

Unit-тесты позволяют сократить цикл "отредактировать, запустить, проверить", если я тестирую логику - потому что для логики есть API и я могу написать Unit-тест. Особенно если речь идет об утилитарных методах/классах типа парсинга текста, вычисления дат и прочих мелочей.

Типичный случай моего использования TDD - если нужно разработать интерфейс сервиса (или бизнес-логики или API, называйте кому как нравится) и проверить его работу.

Unit-тест - это не интеграционный тест (то есть мы уже не можем получить 100% покрытие функциональности; как я говорил выше есть еще тестирование GUI - также вычтите эту часть из 100%), но основные потоки использования сервиса (его интерфейс + usecase) описать и протестировать можно.

TDD очень часто спасал, когда чесались руки спроектировать супер-пупер универсальную иерархию классов - он просто не дает это сделать, позволяя сосредоточиться на требуемом поведении в рамках четко зафиксированных требований. В качестве таких требований я обычно использую основной поток usecase'а.

TDD позволяет придерживаться принципа KISS и он мне нравится уже только поэтому.

Unit-тест TDD - это тестирование логики как черного ящика, что опять же не дает 100% покрытия.

Одно замечание по поводу "кандалов" тестов. Я никогда не пишу тесты, которые бы мне было жалко удалить и переписать. Не нужно проектировать Unit-тесты - достаточно ограничиться рамками метода теста. В этом плане я считаю хорошей практикой написания Unit-тестов TDD подход Copy-Paste.

P.S.

В начальном посте очень много говорится о 100% покрытия кода тестами, а что означает "покрытие кода" автор не приводит. Я думаю и у тестировщиков (что уж там о девелоперах говорить), одного показателя, который измеряется в процентах - нет.

Да, есть инструменты, которые позволяют измерить Code Coverage (например, Cobertura).

Да, они позволяет получить несколько показателей покрытия, но по сути - это такая же размытая оценка о покрытии тестами кода, как и оценка сложности ПО по размеру кода программы в строках.

Такие методики могут быть полезными при оценке проектов, но никак при разработке, и уж точно ничего не говорят о самой методике TDD.

--- Cut ---

2 comments:

  1. Кент Бек приводит в качестве примера функцию проверки треугольника, для полного покрытия которой требуется 64 проверки чтоль... Причем это он озвучивает точку мнения другого человека, сам он, по его словам, обошелся бы гораздо более скромным количеством проверок.

    Метод черного ящика (а какой еще метод может быть перед написанием кода?) гораздо более предпочтительный и скромный по количеству проверок.

    PS: А со старым кодом вообще сложно. :(

    ReplyDelete
  2. Anonymous5:18 PM

    Спасибо за развернутый комментарий.
    Итак, самое главное, на что обратил внимание и я и вы - это 100% покрытие кода тестами. Это и есть камень преткновения и про это моя статья. А не про то, что юнит-тесты вредны или не нужны :)

    100% покрытие юнит тестами значит буквально, что каждая функция и класс в коде должны быть полностью покрыты тестами. "ПОлностью" понятие растяжимое, но обычно это значит "не меньше одного теста на функцию".
    И вот против этого я написал статью.

    А юнит тесты сами по себе полезны и нужны - с этим я не спорю.

    ReplyDelete