Модульное тестирование: 2+2 = 4?

Автор: Андрей Каща
GlobalLogic

Источник: RSDN Magazine #3-2008
Опубликовано: 28.12.2008
Версия текста: 1.0
Зачем эта статья?
Структура
Unit Testing
Путь Тестивуса
Если пишешь код — пиши тесты
Не застряньте в догме юнит тестирования
Примите карму юнит-тестов
Думай о коде и тестах как о едином
Тест важнее, чем юнит
Тестируй, пока свежо
Тесты без запуска — пустая трата времени
Несовершенный тест сегодня лучше совершенного теста когда-нибудь
Ужасный тест лучше, чем никакой
Иногда тест оправдывает средство
Только дураки обходятся без инструментов
Хороший тест падает
Путь Тестивуса
Почему нужно тестировать?
Что тестировать, а что нет?
Сколько должно быть тестов?
Как писать хорошие тесты?
Затрагивает ли написание тестов архитектурные вопросы?
Как быть, если мы сопровождаем старый код?
Case Studies
Case Study #1: Логика сосредоточена в хранимых процедурах.
Case Study #2: Наша система постоянно с кем-то сотрудничает!
Case Study #3: Невозможно сделать этот модуль изолированным!
Case Study #4: Код сильно привязан к окружению (диалоги, потоки, процессы)
Case Study #5: Ваш случай или Вместо Заключения.
Литература

Зачем эта статья?

У нас, в харьковском GlobalLogic’е, появилась традиция: проводим мы неформальные сходки, обсуждаем темы околоайтишные... На одной из таких сходок, посвященной Agile/не Agile процессам, встал вопрос Unit Test’ов. Оказывается, модульное тестирование выглядит очень просто в примерах из книг, но когда мы начинаем применять его на проектах, которые достались нам по наследству, на проектах с нетривиальной многоуровневой архитектурой, тут же сталкиваемся с проблемами.

Посмотрели мы на это дело и решили создать статью, посвященную наиболее распространенным проблемам, с которыми сталкиваются наши разработчики.

Структура

Есть выражение: "Дайте человеку рыбу, и вы накормите его на один день. Научите его ловить рыбу, и он никогда не будет голоден". Именно исходя из этого соображения статья разделена на две части:

1. Unit Testing – здесь рассказывается, почему стоит ловить рыбу (использовать модульное тестирование), и приводятся ссылки на конкретные способы ловли (использования модульного тестирования).

2. Case Studies. Вы уже слышали обо всех "почему", но не верите теории? Сложный, древний проект абсолютно не поддается тестированию? Вероятно, вам будет интересен этот документ. Здесь мы рассмотрим следующие вопросы:

Эта часть больше ориентирована на "матерых" программистов, поскольку здесь затрагивается широкий круг вопросов из областей проектирования дизайна и архитектуры. Знание стандартных паттернов крайне желательно.

Надеюсь, вам понравится. Дайте знать о своих впечатлениях :). Приятного чтения!

Unit Testing

Путь Тестивуса

Прежде чем погрузиться в пучину проблем Unit Test’ов, давайте вооружимся философией Тестивуса (терпение, вскоре мы поймем, кто такой Тестивус). Эта философия отвечает на большинство вопросов и является отличным подспорьем в стране, где живут драконы.

ПРИМЕЧАНИЕ

Так раньше на картах помечались неизведанные места.

Введение переводчика

В мае 2006 года плохо подготовленная экспедиция в Гималаях сбилась с пути. После двух недель скитаний, страдая от голода, жажды и озонируя воздух, как может его озонировать группа затерявшихся на две недели неопытных путешественников, наши страдальцы оказались у входа в древнюю пещеру.

В пещере они увидели лабиринт боксов (cubicles, кабинок). В каждом боксе был деревянный стол, эргономически правильное бамбуковое кресло, календарь Дилберта и странное компьютеро-подобное механическое устройство. В одном углу офиса они нашли запасы темной жидкости (позже определенной как ранний пример газированного напитка с высоким содержанием кофеина) и стол для пинг-понга. Путешественники поняли, что пещера была древним софтверным стартапом. Самым древним. Древнее даже чем Netscape...

Среди прочих замечательных вещей они нашли нечто потрясающее: записку, оставленную одним из программистов. Гид экспедиции, будучи не очень хорошим гидом, знал, как читать древний язык, и перевел записку:

Мы выкатили релиз раньше срока, как обычно. Все тесты проходят, так что в оставшуюся неделю мы решили отдохнуть. Собираемся в морское путешествие. Поскольку это занятие по тим-билдингу, мы надеемся, что получим возмещение расходов.

Путешественники смотрели друг на друга в полном недоумении. Они не только открыли самый древний софтверный стартап в истории, но еще и команду разработчиков, которая оказывается релизилась впереди расписания на постоянной основе!

Каков был секрет древних программистов? И что с ними случилось? Путешественники обрыскали каждый бокс в поисках зацепок, и нашли две заношенные брошюры. Одна из них называлась "Научись путешествовать по морю за 30 минут", что объясняло судьбу программистов. Вы держите в руках перевод второй брошюры "Путь Тестивуса". Кто написал ее? Что такое Тестивус? Одному Гуглу известно наверняка...

Объясняет ли содержимое этого текста успехи древних программистов? Нельзя сказать точно, но мы верим, что их потрясающая доблесть обязана комбинации философии Тестивуса и приему в больших количествах темной жидкости с кофеином, найденной в пещере. Прочитайте брошюру и сделайте свои выводы.

Alberto Savoia, CTO/Cofounder of Agitar Software
Апрель 2007, Mountain View, Calif.

Если пишешь код — пиши тесты

Ученик спросил мастера-программиста:

"Когда я могу перестать писать тесты?"

Мастер ответил:

"Когда ты перестаешь писать код"

Ученик спросил:

"Когда я перестаю писать код?"

Мастер ответил:

"Когда ты становишься менеджером"

Ученик задрожал и спросил:

"Когда я становлюсь менеджером?"

Мастер ответил:

"Когда ты перестаешь писать тесты"

Ученик побежал писать тесты.

Остались только следы.

Если код заслуживает быть написанным, он заслуживает иметь тесты.

Не застряньте в догме юнит тестирования

Догма говорит:

"Делай это.
Делай только это.
Делай это только так.
И делай это потому, что я тебе говорю"

Догма не гибкая.

Тестированию нужна гибкость.
Догма убивает творчество.

Тестированию нужно творчество.

Примите карму юнит-тестов

Карма говорит:

"Делай хорошие вещи, и хорошие вещи произойдут с тобой.
Делай их так, как ты знаешь.
Делай их так, как тебе нравится".

Карма гибка.

Тестированию нужна гибкость.

Карма процветает на творчестве.

Тестированию нужно творчество.

Думай о коде и тестах как о едином

Когда пишешь код, думай о тесте.

Когда пишешь тест, думай о коде.

Когда ты думаешь о коде и тесте как о едином,

тестирование просто, а код красив.

Тест важнее, чем юнит

Ученик спросил великого мастера программирования Летящего Пера:

"Что превращает тест в юнит-тест?"

Великий мастер программирования ответил:

"Если он обращается к базе, значит, он не юнит-тест.
Если он обращается к сети, значит, он не юнит-тест.
Если он обращается к файловой системе, значит, он не юнит-тест.
Если он не может выполняться одновременно с другими тестами, значит, он не юнит тест.
Если ты должен делать что-то с окружением, чтобы выполнить тест, значит, он не юнит тест".

Другой мастер-программист присоединился и начал возражать.
"Извините, что я спросил", — сказал ученик.
Позже ночью он получил записку от величайшего мастера-программиста. Записка гласила:

"Ответ великого мастера Летящего Пера прекрасный ориентир.
Следуй ему, и в большинстве случаев не пожалеешь.
Но не стоит застревать на догме.
Пиши тест, который должен быть написан".

Ученик спал хорошо.
Мастера все еще продолжали спорить глубокой ночью.

Тестируй, пока свежо

Твой код — как глина.
Пока она свежая — она мягкая и податливая.
Со временем она становится твердой и хрупкой.
Если ты пишешь тесты, пока код свежий и легко изменяемый —
тестирование будет проще, а код вместе с тестами будет прочнее.

Тесты без запуска — пустая трата времени

Запускай тесты часто.
Не позволяй им застаиваться.
Радуйся, когда они проходят.
Радуйся, когда они не проходят.

Несовершенный тест сегодня лучше совершенного теста когда-нибудь

Лучшее — враг хорошего.
Не жди лучшего, чтобы сделать лучше.
Не жди лучшего, чтобы сделать хорошо.
Напиши тест, какой сможешь, сегодня.

Ужасный тест лучше, чем никакой

Когда код ужасен — тесты могут быть ужасны.
Ты не любишь писать ужасные тесты,
Но ужасный код нуждается в тестах больше всего.
Не разрешай ужасному коду отговорить тебя писать тесты,
Но позволь ужасному коду отговорить тебя писать ужасный код в будущем

Иногда тест оправдывает средство

Ученик спросил двух мастеров-программистов:

"Я не могу написать этот код без создания моков и нарушения инкапсуляции.
Что мне делать?"

Один мастер программист ответил:

"Моки — это плохо, и ты никогда не должен нарушать инкапсуляцию.
Перепиши код, чтобы можно было тестировать правильно".

Другой мастер ответил:

"Моки — это хорошо, и тестирование важнее инкапсуляции".

Обескураженный ученик ушел за пивом. В местной пивной он встретил
Величайшего мастера-программиста, посасывающего пивко с куриными крылышками.

"Величайший мастер!" — сказал ученик, — "Я думал, что вы не пьете.
И разве вы не вегетарианец?"

Величайший мастер улыбнулся и ответил:

"Иногда жажда лучше утоляется пивом, а голод — куриными крылышками".

Ученик больше не был обескуражен.

Только дураки обходятся без инструментов

Фермер без плуга — плохой фермер.
Счетовод без абака — плохой счетовод.
Некоторые задачи лучше выполняются голыми руками.
А некоторые — инструментами.
Нет ничего благородного делать что-то руками,
что может быть лучше сделано с инструментом.
Неразумно использовать голову там, где она не нужна.

Хороший тест падает

Ученик подошел к мастеру-программисту и сказал:

"Все мои тесты всегда проходят. Не заслуживаю ли я повышения?"

Мастер отвесил леща ученику и ответил:

"Если все твои тесты всегда проходят, тебе стоит лучше писать тесты"

С красной шеей пошел ученик жаловаться в HR.
Но это уже другая история...

Путь Тестивуса

Если пишешь код — пиши тесты.
Не застряньте в догме юнит тестирования.
Примите карму юнит тестов.
Думай о коде и тестах как о едином.
Тест важнее, чем юнит.
Тестируй, пока свежо.
Тесты без запуска — пустая трата времени.
Несовершенный тест сегодня лучше совершенного теста когда-нибудь.
Ужасный тест лучше, чем никакой.
Иногда тест оправдывает средство.
Только дураки обходятся без инструментов.
Хороший тест падает.

Оригинал статьи можно найти по адресу [1].

Не стоит воспринимать этот рассказ как догму. Думайте о нем, как об "еще одной точке зрения".

Почему нужно тестировать?

Что тестировать, а что нет?

Сколько должно быть тестов?

Как писать хорошие тесты?

Затрагивает ли написание тестов архитектурные вопросы?

Как быть, если мы сопровождаем старый код?

Case Studies

Case Study #1: Логика сосредоточена в хранимых процедурах.

Case Study #2: Наша система постоянно с кем-то сотрудничает!

Case Study #3: Невозможно сделать этот модуль изолированным!

Case Study #4: Код сильно привязан к окружению (диалоги, потоки, процессы)

Case Study #5: Ваш случай или Вместо Заключения.

Литература

  1. Alberto Savoia The Way of Testivus - Unit Testing Wisdom From An Ancient Software Start-up
  2. Кент Бек – Экстремальное программирование.
  3. Кент Бек – TDD.
  4. Gerard Meszaros – xUnit Test Patterns.
  5. Gerard Meszaros - http://xunitpatterns.com/index.html
  6. Martin Fowler – Patterns of Enterprise Application Architecture.
  7. Martin Fowler – Refactoring.
  8. Steve McConnell – Code Complete.
  9. GoF – Design Patterns.
  10. Michael Feathers - Working Effectively with Legacy Code.


Полная версия этой статьи опубликована в журнале RSDN Magazine #3-2008. Информацию о журнале можно найти здесь