Забавно, как всё меняется. Пятнадцать лет я свято придерживался принципов TDD (разработка через тестирование, или, как её раньше называли, подход test-first) или уж по крайней мере того взгляда, что разработчикам следует писать юнит-тесты. Но в последнее время я всё чаще говорю не «Это нужно затестить», а «Зачем вы писали этот тест?».
![](https://habrastorage.org/r/w780q1/web/c1b/7d7/23c/c1b7d723cfd9409fb23d3cbee0698d05.jpeg)
Как-то раз, когда я проходил по офису, меня остановил один разработчик и попросил помочь с юнит-тестами. У него возникли какие-то сложности при использовании Mockito для тестирования вот этого кода:
![](https://habrastorage.org/r/w1560/web/040/0f9/9f2/0400f99f23cf4cbba6ada77911cf84e5.png)
Мой ответ его, кажется, удивил. Я сказал: «Это не нужно тестировать».
«Конечно, нужно!» — ответил он. «Как я иначе узнаю, что всё работает?»
«Это совершенно прозрачный код. В нём ничего такого нет: ни атрибутов conditional, ни циклов, ни трансформаций. Просто обычный кусок связующего кода».
«Но если не провести тест, кто угодно может прийти, внести какие-нибудь изменения и всё сломать!»
«Послушай, пусть даже этот воображаемый недотёпа или злодей действительно придёт и всё испортит — как ты думаешь, что он сделает, когда соответствующий юнит-тест провалится? Удалит, и все дела».
«Ну а если бы тебе пришлось писать тест?»
«В таком случае я бы вышел из положения вот так».
![](https://habrastorage.org/r/w1560/web/a26/753/908/a267539082634c6aa0d8defae567ab3b.png)
«Но ты же не используешь Mockito!»
«И что? Mockito никак здесь тебе не помогает. Даже наоборот, мешается. С ним тест не станет ни проще, ни читабельнее».
«Но мы же решили, что будем проводить все тесты с помощью Mockito!»
Мой ответ: «…»
Когда я в следующий раз с ним столкнулся, он с гордостью поведал мне, что всё-таки сумел написать этот тест на Mockito. Я понимаю, какое удовлетворение испытываешь, когда получается заставить что-то работать, и всё же мне как-то взгрустнулось.
Другой раз меня подозвал разработчик, окрылённый высоким покрытием кода одного из своих новых приложений и вспыхнувшей любовью к BDD (разработке на основе поведения). Просматривая код, мы нашли такой тест на Cucumber:
![](https://habrastorage.org/r/w1560/web/317/ba4/97e/317ba497e4bc41528ee21a74a7b2393f.png)
Тех, кто работал с Cucumber, не удивит объём вспомогательного кода, которого он требует:
![](https://habrastorage.org/r/w1560/web/8fa/a32/cb3/8faa32cb3bc54e1aa90f58c6336d5509.png)
![](https://habrastorage.org/r/w1560/web/342/913/20e/34291320eef84e0fa9d92846bb48778e.png)
И всё это ради того, чтобы протестировать следующее:
![](https://habrastorage.org/r/w1560/web/bea/bab/d2a/beababd2a77c45568417a6799af1e328.png)
Да-да, простой map lookup. У меня были достаточно доверительные отношения с этим разработчиком, чтобы сказать ему без обиняков: «Столько времени потрачено впустую».
Он ответил: «Но мой начальник рассчитывает, что я буду писать тесты для всех классов».
«И во что это тебе обходится?»
«Обходится?»
«К тому же, этого не имеет никакого отношения к BDD».
«Знаю, но мы решили проводить все тесты при помощи Cucumber».
Мой ответ: «...».
Я понимаю, какое удовлетворение испытываешь, когда удаётся приспособить инструмент под свои нужды, и всё же мне как-то взгрустнулось.
Трагедия в том, что двое талантливых разработчиков (я бы охотно сходил с ними на командное интервью) убивают время на подобные тесты — тесты, от которых никакого проку и которые следующим поколениям разработчиков из IG придётся поддерживать в рабочем состоянии.
Трагедия в том, что вместо того, чтобы выбрать подходящий инструмент для работы, мы мучаемся с теми, которые совершенно не годятся, и сами не знаем зачем.
Трагедия в том, что, когда «хорошая практика» становится общепринятой, мы будто забываем, как к ней пришли, какие преимущества она предлагает, и — самое-то главное — каких затрат она требует.
Вместо того, чтобы иметь это всё в виду, мы просто автоматически применяем её, особо не задумываясь, и в итоге получаем весьма посредственные результаты — теряем большую часть преимуществ, а платим при этом полную цену (иногда и с накруткой). Мой опыт говорит, что создание качественных юнит-тестов — работа непростая.
Да, это должен проделать каждый… но только в рамках одного проекта.
У нас более чем достаточно примеров одной крайности: проектов без единого юнит-теста, и мы уже знаем, как мучительно с ними работать. Но мало у кого есть опыт взаимодействия с противоположной крайностью: проектов, где требуют стопроцентного покрытия кода и во всём придерживаются TDD. Юнит-тесты (особенно те, где реализуется подход test first) — отличная практика, но нам необходимо понимать, какие тесты полезны, а какие — только снижают продуктивность.
Помните: ничто не обходится нам даром, палочек-выручалочек не существует. Всегда лучше остановиться и подумать.
![](https://habrastorage.org/web/c1b/7d7/23c/c1b7d723cfd9409fb23d3cbee0698d05.jpeg)
Почему так?
Как-то раз, когда я проходил по офису, меня остановил один разработчик и попросил помочь с юнит-тестами. У него возникли какие-то сложности при использовании Mockito для тестирования вот этого кода:
![](https://habrastorage.org/web/040/0f9/9f2/0400f99f23cf4cbba6ada77911cf84e5.png)
Мой ответ его, кажется, удивил. Я сказал: «Это не нужно тестировать».
«Конечно, нужно!» — ответил он. «Как я иначе узнаю, что всё работает?»
«Это совершенно прозрачный код. В нём ничего такого нет: ни атрибутов conditional, ни циклов, ни трансформаций. Просто обычный кусок связующего кода».
«Но если не провести тест, кто угодно может прийти, внести какие-нибудь изменения и всё сломать!»
«Послушай, пусть даже этот воображаемый недотёпа или злодей действительно придёт и всё испортит — как ты думаешь, что он сделает, когда соответствующий юнит-тест провалится? Удалит, и все дела».
«Ну а если бы тебе пришлось писать тест?»
«В таком случае я бы вышел из положения вот так».
![](https://habrastorage.org/web/a26/753/908/a267539082634c6aa0d8defae567ab3b.png)
«Но ты же не используешь Mockito!»
«И что? Mockito никак здесь тебе не помогает. Даже наоборот, мешается. С ним тест не станет ни проще, ни читабельнее».
«Но мы же решили, что будем проводить все тесты с помощью Mockito!»
Мой ответ: «…»
Когда я в следующий раз с ним столкнулся, он с гордостью поведал мне, что всё-таки сумел написать этот тест на Mockito. Я понимаю, какое удовлетворение испытываешь, когда получается заставить что-то работать, и всё же мне как-то взгрустнулось.
Другой пример
Другой раз меня подозвал разработчик, окрылённый высоким покрытием кода одного из своих новых приложений и вспыхнувшей любовью к BDD (разработке на основе поведения). Просматривая код, мы нашли такой тест на Cucumber:
![](https://habrastorage.org/web/317/ba4/97e/317ba497e4bc41528ee21a74a7b2393f.png)
Тех, кто работал с Cucumber, не удивит объём вспомогательного кода, которого он требует:
![](https://habrastorage.org/web/8fa/a32/cb3/8faa32cb3bc54e1aa90f58c6336d5509.png)
![](https://habrastorage.org/web/342/913/20e/34291320eef84e0fa9d92846bb48778e.png)
И всё это ради того, чтобы протестировать следующее:
![](https://habrastorage.org/web/bea/bab/d2a/beababd2a77c45568417a6799af1e328.png)
Да-да, простой map lookup. У меня были достаточно доверительные отношения с этим разработчиком, чтобы сказать ему без обиняков: «Столько времени потрачено впустую».
Он ответил: «Но мой начальник рассчитывает, что я буду писать тесты для всех классов».
«И во что это тебе обходится?»
«Обходится?»
«К тому же, этого не имеет никакого отношения к BDD».
«Знаю, но мы решили проводить все тесты при помощи Cucumber».
Мой ответ: «...».
Я понимаю, какое удовлетворение испытываешь, когда удаётся приспособить инструмент под свои нужды, и всё же мне как-то взгрустнулось.
В чём трагедия?
Трагедия в том, что двое талантливых разработчиков (я бы охотно сходил с ними на командное интервью) убивают время на подобные тесты — тесты, от которых никакого проку и которые следующим поколениям разработчиков из IG придётся поддерживать в рабочем состоянии.
Трагедия в том, что вместо того, чтобы выбрать подходящий инструмент для работы, мы мучаемся с теми, которые совершенно не годятся, и сами не знаем зачем.
Трагедия в том, что, когда «хорошая практика» становится общепринятой, мы будто забываем, как к ней пришли, какие преимущества она предлагает, и — самое-то главное — каких затрат она требует.
Вместо того, чтобы иметь это всё в виду, мы просто автоматически применяем её, особо не задумываясь, и в итоге получаем весьма посредственные результаты — теряем большую часть преимуществ, а платим при этом полную цену (иногда и с накруткой). Мой опыт говорит, что создание качественных юнит-тестов — работа непростая.
Так стоит ли обрабатывать код целиком?
Да, это должен проделать каждый… но только в рамках одного проекта.
У нас более чем достаточно примеров одной крайности: проектов без единого юнит-теста, и мы уже знаем, как мучительно с ними работать. Но мало у кого есть опыт взаимодействия с противоположной крайностью: проектов, где требуют стопроцентного покрытия кода и во всём придерживаются TDD. Юнит-тесты (особенно те, где реализуется подход test first) — отличная практика, но нам необходимо понимать, какие тесты полезны, а какие — только снижают продуктивность.
Помните: ничто не обходится нам даром, палочек-выручалочек не существует. Всегда лучше остановиться и подумать.