Я почувствовал, что устои мироздания потрясены, когда сотни читательов начали яростно спорить по поводу заметки Роберта Мартина о стартапе-ловушке.
Хотите знать, как я обычно участвую в таких спорах?
— Так какие же тесты пишешь ты сам?
— Мнэ-э…
— Когда же ты пишешь тесты?
— Мнэ-э…
— Ты вообще тесты пишешь?
— Мнэ-э…
Окей, конечно, я пишу тесты, я просто не участвую в таких спорах. Времена, когда нас всех заставили принять таблетку TDD, провели черту между теми программистами, которые полюбили тесты всем сердцем, и теми, кто на самом деле не очень-то любит писать тесты. И ввязываться в спор между двумя этими лагерями — отличный повод потерять пару часов впустую, вместо того чтобы делать свою работу.
Но как раз сейчас у меня, кажется, есть эта парочка часов.
Классическое TDD, то самое, которое говорит, что тесты «не должны ничего знать» о реализации, о настоящем коде — умерло, поезд ушел, все кончено. Но несомненно, его недолгое присутствие произвело ожидаемый эффект — все задумались о коде, который уже написан и задумались о написании для него тестов, чтобы при изменении кода в будущем не возникало проблем.
Проблемы.
Это важно. Проблемы. Повторите еще раз — Проблемы. Если вам неприятно, давайте решать эти проблемы.
- У вас очень много тестов, которые приходится удалять, если какая-то фича оказалась ненужной? Ну так не пишите их так много — вы скорее всего экспериментируете с продуктом, и, возможно, подход «исследуй и стабилизируй» подойдёт вам лучше.
- Вам трудно вносить изменения в код, потому что при этом сразу всё ломается, и компоненты очень сильно-связаны? Напишите несколько тестов на эту подсистему, попробуйте test-first подход при написании нового кода, и проблемы с сильной связанностью будут решены.
- Вам приходится танцевать с бубном вокруг маленькой фичи, потому что вы стремитесь к тончайшему юнит-тестированию, а это значит, что приходится добавлять тонны кода там, где хватило бы простых CRUD-операций? Остановитесь, подумайте об интеграционном тестировании и об использовании in-memory БД для ускорения тестов.
Прислушиваться к проблемам — единственный разумный путь при разработке ПО. Одна крайность — Роб Мартин — заведет вас в глубокие дебри. Другая — те, кто призывают не думать об опасностях вовсе — скорее всего приведет вас к провалу. Мысль, что тесты — это просто потеря времени, очень опасна, особенно если эта мысль пустит корни в вашем сознании. Но и идея об абсолютной важности TDD — не менее опасна.
Когда вы пишете по классическому ТДД, вы теряете большую часть денег вашего заказчика, но если вы не пишете тестов вообще, то вам придется потратить все это время еще раз — в будущем.
Классическое TDD — это отличный теоретический прием, с которым можно поиграться в свободное время или на выходных. Классическое TDD — отличный маркетинговый слоган, если вы — один из тренеров или TDD-коучей. Да, TDD — этот пункт, на который обязательно смотрят при приеме на работу, но TDD — это обычно не тот путь, которым идет отличное приложение, сделанное в срок.
Так какие же тесты ты всё-таки пишешь?
- Я обычно использую подход «исследуй и стабилизируй» для тех фичей, которые, возможно, будут в итоге исключены из конечного продукта. Таким образом я не трачу время на тесты раньше, чем нужно, и получаю обратную связь по новым возможностям так быстро, как это только возможно.
- Я обычно начинаю с интеграционных тестов, заменяя все медленные части на их представления, работающие с памятью (например, заменяя БД на in-memory БД в тестах).
- Я спускаюсь на уровень юнит-тестов, если вижу сложную логику (как ни странно, большинство систем — это обычные CRUD, так что это необязательно)
- Сценарии использования обычно проверяются с использованием UI как часть приемочных тестов, поскольку это именно то, что видит пользователь.
Итого
Есть два типа прагматиков, когда дело доходит до тестирования. Те, кто говорят о прагматизме, чтобы не делать нужные вещи, и я.
От переводчика: Rob Ashton — известный фриланс-разработчик из Европы, участвующий во многих open-source проектах.
Автор: Shaddix