Re[4]: Проектирование системы с учетом юнит-тестирования
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 05.12.12 13:14
Оценка: 19 (4)
Здравствуйте, 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
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.