Здравствуйте, landerhigh, Вы писали:
B>>А не посоветуешь умную книжку, желательно по-проще, с карнтинками и с упором на выгоды юнит-тестов? (для агитации местного населения)
L>Честно говоря, сам хочу найти. Не уверен, что такая существует. Это же сугубо практическая вещь, теорию на юнит-тестирование натягивать ИМХО бесполезно.
L>По опыту, агитация действует не очень. Лучше всего работает быстрый проект, которым рулит евангелист TDD или просто юнит-тестирования (в завсимости от публики ему может быть очень желательно быть еще и фашистом или просто диктатором)
В упомянутой выше The Art of Unit Testing есть целый раздел по поводу продвижения (как я уже сказал выше).
А продвигать приходится как всегда: примером, причем желательно собственным и позитивным (т.е. они для вас должны приносить пользу).
Как-то недавно пробегал твит от кого-то из TDD-гуру: что если бы каждый раз, когда юнит-тест находил баг, человек бы подпрыгивал и кричал "Ура! Тест сработал!", то все значительно лучше бы осознавали их ценность
Если серьезно, то очень здорово покрыть тестами (юнит или интеграционными) наиболее хрупкие части системы, и показывать их преимущества изо дня в день.
Помимо этого может сработать ненавязчивое проталкивание этой техники во время код- или дизайн-ревью с помощью вопросов:
Ты: — Вот смотри, как бы ты писал юнит тест для своего класса/модуля?
Он: — Ну, не знаю, а зачем мне это нужно, да и вообще, сложно это...
Ты: — Ну раз ты не можешь написать юнит-тест, значит ты не можешь думать о своем классе/модуле в изоляции. А значит у него нет четких входов/выходов (или их слишком много), что говорит о проблемах с дизайном. Если модуль тяжело протестировать, то его будет тяжело (или невозможно) использовать в другом контексте, что ставит полный крест на повторном использовании.
Он: — Ну ладно, но все равно, как-то не хочется из-за таких "мелочей" тратить время.
Ты: — А ты посмотри с другой стороны: ты не просто тратишь время один раз, ты бережешь его для себя и своей команды в будущем. Ведь тесты можно использовать, как еще один клиент твоего класса/модуля. Нормальный тест будет является своего рода источником спецификации системы и мы можем использовать эту информацию повторно. Да и вообще, ведь тебе, чтобы доделать задачу, все равно придется потратить время на запуск всей этой сложной системы, причем делать это придется каждый раз и не только тебе, но и твоим коллегам. Юнит-тест может просто сберечь твое время, поскольку ты сможешь потратить времени в 10 раз меньше на проверку этой маленькой функции.
Он: — Ну, не убедил окончательно... А какие есть у этого дела еще выгоды?
Ты: — Ну, если этого мало
Давай подумаем об интеграции. Ведь у нас постоянная проблема с параллельной разработкой упирается в интеграцию. Вспомни, как ты с Васей долелали куски одной задачи и начали их интегрировать. На задачу ушло неделю, а потом вы бились головами еще три недели, чтобы объединить эти два куска и заставить их работать вместе. Тест дают некоторый формализм и значительно упрощают интеграцию. Ты вспомни того же Буча:
любая сложная система строится на основе проверененных маленьких строительных блоков. А как нам получить
проверенные строительные былоки, если мы не будем тестировать их вначале в изоляции? Вот и получается, что у нас есть огромная плоская система, на которой мы постоянно проверяем эффект бабочки: изменяем одну часть системы, а в продакшне летит совершенно другая ее часть.
Ну и не забывай о рефакторинге: без тестов (юнит и интеграционных) мы не можем зафиксировать текущее поведение, чтобы изменить ее внутреннюю реализацию. Тесты выступают в роли таких себе "тисков", в которые мы зажимаем систему, чтобы она не дергалась. Без этого процесс рефакторинга становится совершенно неуправляемым, а ведь мы-то с тобой знаем, что придет время, когда мы с тобой скажем: "А давай-ка тут немного переделаем!", так давай заложимся на это с самого начала.
Он: — Ну ладно, так давай подытожим, чего же мы получим в результате.
Ты: — Ну, ладно, вот небольшой список пользы юнит-тестов:
1. Юнит-тесты — лакмусовая бумажка плохого дизайна. Если у нас нет мыслей, как это дело потестить, то с дизайном явно что-то не то.
2. Юнит-тесты — дополнительный источник спецификации системы. Код сам по себе не может быть правильным или не правильным. Все зависит от того, что мы от него ожидаем (а тесты как раз и показывают "ожидаемое" поведение системы).
3. Юнит-тесты помогают использовать повторно наши усилия: подумать раз и заперсистентить наши мысли в форме тестов.
4. Юнит-тесты могут даже ускорить разработку. Если для проверки фичи нужно 5 минут, то 20 минут на написание теста с последующей секундной проверкой будет более эфективным использованием времени даже в краткосрочной перспективе.
5. Юнит-тесты упрощают интеграцию. Хорошо продуманные кусочки легко объединять и, что самое главное, легко "перемещать" из одного места системы в другое.
6. Юнит-тесты — это — это необходимый background для рефакторинга. Без них рефакторинг превращается в серьезную авантюру.
Но есть и явный вред от них:
1. Плохие юнит-тесты — хуже чем их отсутствие. Они должны тестировать абстракцию, и не вдаваться в подробности реализации. Тест, который постоянно падает будет удален. Тест, в котором невозможно разобраться, будет удален. Тест, который падает через раз — будет удален. Тест, который работает полдня — будет удален. Тест, который постоянно ломается при несущественных изменениях реализации — будет удален.
2. Тесты — не самоцель. Не гонитесь за покрытием, будьте прагматиками. Тестируйте важные части системы и не тестируйте глупости.
А еще рекомендую послушать следующие два подкаста Кента Бека (они очень круто меняют взгляд на юнит тесты):
1.
Software Engineering Radio Episode 167 – The History of Junit and the Future of Testing with Kent Beck
2.
Development Testing with Kent Beck