нужно писать TDD тесты.
Нет, нет такой вещи как "TDD тесты". TDD это одна из методик экстремального программирования (XP). Вам уже привели ссылку на книгу Кента Бэка на эту тему (к слову крайне рекомендую)
Суть этой методологии в том, что бы разбить работу над кодом на три этапа, которые называются циклом красный-зеленый-рефакторинг.
-
Красный - перед тем как написать код, мы должны написать тест который ломается (обычно в консоли сломанные тесты подсвечиваются красным). Согласно этой методологии писать код вы должны строго тогда, когда у вас есть сломанные тесты. Если сломанных тестов нет, то и код писать не нужно.
-
Зеленый - когда вы получили красные тесты, вы должны максимально быстро дописать код так. что бы тесты были зелеными. Скажем если вы написали тест который ожидает от функции, что она вернет строку "foo" то в коде у вас должно быть не больше чем сама функция и вывод строки "foo". Как только мы этого добились мы либо рефакторим, либо добавляем еще красных тестов что бы потом дописать код. Конечно настолько примитивные вещи делать по такому циклу избыточно, и у Кента Бэка описывается понятие "длины шага", то есть сколько работы мы можем делать на каждом этапе. Вы всегда должны подключать здравый смысл словом.
-
Рефакторинг - на предыдущих фазах мы не загонялись о том насколько наш код красив, насколько мы соблюдали принципы DRY и т.д. так что это фаза отчистки кода. Мы можем делать ее на каждой итерации, а можем раз в пару часов, но важно делать это как можно чаще. На этом этапе мы устраняем дублирование как в коде приложения так и в тестах. Важно отметить что хорошей мыслью будет не рефакторить одновременно и код и тесты, ибо у нас должен быть источник правды. Если мы почистили тесты и при этом они начали фэйлиться, то значит мы что-то сломали пока числити. И наоборот. А если менять и то и то между запусками тестов то не понятно кто виноват.
Обычно TDD практикуют используя unit-тесты (что логично, ибо они выполняются достаточно быстро что бы выполнение тестов не заставляло нас заваривать чай), что подразумевает собой то, что мы тестируем один юнит (один класс или объект), а все его зависимости должны подменяться на моки (фэйковые объекты, которые нужны что бы проверить как наш объект взаимодействует с другими, об этом тоже много написано). Но никто не запрещает использовать интеграционные/функциональные тесты и при этом практиковать TDD (так например делают чуваки практикующие BDD), а Кент Бэк это дело называет ATDD.
Собственно TDD дает нам следующие преимущества:
- вы не тратите время на проектирование системы в микроскопических масштабах, это эволюционный подход, архитектура приложения постоянно меняется и эволюционирует вместе с требованиями. Все требования формализуются в виде тестов.
- код всегда покрыт тестами (пусть и не на 100%, обычно хватает и 20% что бы можно было жить, все зависит от сроков жизни проекта и требуемого уровня надежности)
- если вам становится трудно писать тесты (например много зависимостей, сложно мокать) - то это должно навести вас на мысль о не правильной архитектуре и инициировать более глубокий рефакторинг. А при наличии тестов это не так уж и страшно.
- необходимость покрывать тесты увеличивает потребность в соблюдении всяких принципов типа SOLID и т.д. так как иначе мы начинаем писать тесты очень не эффективно и опять же возвращаемся к тому что с архитектурой что-то не так.
updated
тут в комментариях уличили в том что я не указал минусы и область использования методологии...
Минусы TDD проистекают из плюсов. Это эволюционный подход, который хорошо работает когда мы вносим изменения в систему маленькими порциями и всегда рефакторим наш код, что бы он большую часть времени был красивым и удобным к расширению. Если же вам в руки дали легаси проект и сказали отрефакторить, то TDD тут не подходит или подходит плохо. Но опять же такая задача ставится довольно редко, чаще - добавление функционала. И в этом случае мы возвращаемся к внесению изменений маленькими порциями и эволюционному подходу. Просто на это уйдет довольно много времени, но если сравнивать с "рефакторинг + добавление функционала + регрессионное тестирование" то в зависимости от ситуации TDD может дать как профит так и нет. Все зависит от сложности системы. На простых системах в этом нет смысла.
По поводу области применения... Тут есть несколько точек зрения. Как минимум TDD решает вопрос проектирования архитектуры, а не разработки алгоритмов. Этого мы достигаем тестами. Но опять же через юнит тестирование довольно не удобно разрабатывать определенные типы проектов: комиляторы, трансляторы, различные решения основанные на сложных алгоритмах (например алгоритмы сжатия, шифрования и т.д.), штуки завязанные на сетевом взаимодействии, например клиенты для протоколов. Для этих вещей больше подходят функциональные тесты или же их вовсе сложно покрыть тестами.