Разделы портала

Онлайн-тренинги

.
Фоновое модульное тестирование: новый виток развития интеграции модульных тестов и сред разработки
11.02.2009 14:24

Автор: Джон Смарт (John Smart)

Оригинальная публикация: Background Unit Testing: New evolutions in unit testing and IDE integration

Об авторе: Джон Смарт -- ведущий консультант компании Wakaleo Consulting, специализирующейся в области Enterprise Java, Web Development и Open Source technologies. В настоящее время он проживает в Веллингтоне, Новая Зеландия. Джон широко известен в Java-сообществе благодаря многочисленным публикациям, кроме того, он является автором Java Power Tools.

Одна из самых последних инноваций в модульном тестировании – идея непрерывного тестирования, то есть выполнение модульных тестов сразу же после того, как вы изменили что-то в исходном коде – то есть, как только вы сохраняете сделанные изменения на диск, нужные модульные тесты выполняются в фоновом режиме. Это позволяет избежать ситуаций, когда разработчик либо забыл, либо по какой-то другой причине не выполнил нужные тесты,  в результате чего в репозиторий попадает код, на котором эти тесты завершаются неуспешно. Разумеется, главная сложность заключается в том, чтобы определить, какие же тесты следует выполнить, когда изменился тот или иной фрагмент исходного кода, поскольку выполнять полный комплект тестов может быть слишком долго, чтобы делать это после каждого изменения кода. Нужно выделить ровно те тесты, на результат выполнения которых в наибольшей степени могут оказать влияние сделанные изменения. Я уверен, что через пару лет это станет стандартной встроенной функциональностью во всех средах разработки.

А пока этого не случилось, вы можете воспользоваться вспомогательными инструментами.

Мне известны два инструмента, представляющих такие возможности. Первый, JUnitMax, разработал Кент Бек, один из пионеров экстремального программирования (Extreme Programming, XP) и разработки через тестирование (Test Driven Development, TDD). Второй инструмент – Infinitest. Infinitest бесплатный и с открытым кодом, а JUnitMax доступен по подписке (в настоящее время цена составляет $2 в месяц; цена, на мой взгляд, смешная, но для кого-то это может оказаться достаточной причиной, чтобы отказаться от попытки попробовать, это досадно). Оба инструмента весьма неплохи, хотя документация бедновата (впрочем, здесь можно найти неплохую инструкцию по использованию JUnixMax).

Infinitest отличается тем, что он может работать как с Eclipse, так и с IntelliJ, тогда как JUnitMax поддерживает только Eclipse. На самом деле Infinitest представляет собой автономное Java-приложение, которое запускается из Eclipseобычным способом, через меню Run. То есть интеграция со средой разработки не слишком тесная, хотя имеется подробная пошаговая инструкция по использованию Infinitest в Eclipse. К сожалению, когда я «натравил» его на один из модулей в моём многомодульном проекте со сборкой через Maven, он не смог определить, где там находятся тесты.

JUnitMax поставляется как плагин к Eclipse, так что он встраивается в среду разработки более гладко. Для эксперимента я сделал несколько тривиальных изменений в одном из моих модульных тестов. Когда я сохранил изменения, как я и предполагал, JUnitMax запустил некоторые тесты в фоновом режиме, при этом обнаружилась ошибка сборки, чего я совершенно не ожидал! JUnixMax работает как невидимка и поднимает шум только в том случае, когда какой-то тест завершается неуспешно. Но уж в этом случае сообщение об ошибке теста показывается так же, как обычно показываются ошибки компиляции, то есть прямо на полях в исходном коде. Это очень удобно – неуспешное завершение модульных тестов трактуется как проблема того же уровня важности, что и ошибка компиляции, что заметно повышает наглядность. Это также повышает и производительность труда – вам не нужно помнить о том, чтобы запускать модульные тесты после каждого сохранения изменений, и не нужно ждать, пока тесты выполнятся (возможно, даже прерывая из-за этого на какое-то время основную работу). Естественно, неуспешно завершившиеся тесты помечаются также специальными флагами в дереве проекта, так что вряд ли вы сможете не заметить этого, даже если ошибка проявилась там, где вы меньше всего ожидали.

Конечно, контроль за поддержанием модульных тестов в актуальном состоянии – это великолепно, но гораздо важнее возможность запуска нужных тестов после  того, как изменился какой-то класс в реализации. Для проверки я  сделал кое-какие исправления в исходном коде, внеся при этом ошибку. И через несколько секунд на соответствующих модульных тестах появилась красная метка.

Как я уже говорил, самое важное – определить, какие тесты нужно выполнить, чтобы вы как можно быстрее узнали о том, что некоторые тесты завершаются неуспешно. JUnitMax использует некие хитрые эвристики, чтобы догадаться, какие тесты следует выполнять, в первую очередь он старается запустить те тесты, которые выполняются быстрее всего. Но к концу дня все ваши модульные тесты выполняются после каждого изменения. Это приближённый способ определения нужных тестов, но в целом он работает нормально. Более точная техника должна основываться на информации о покрытии кода, чтобы определить, какими тестами покрывается каждая строка кода. Это гораздо сложнее. Clover может делать это, но не в режиме реального времени. Например, если вы используете Clover, интегрированный в систему сборки Maven, в процессе сборки Maven может выполнять только нужное подмножество модульных тестов, выбираемое на основании того, какие части кода изменились, и какие тесты покрывают эти части кода. Это отличный способ ускорить процесс сборки, но пока он ещё не на той стадии развития, чтобы можно было его гладко интегрировать в среду разработки, как это сделано в JUnitMax. Более совершенный JUnitMax мог бы сочетать эти две технологии, чтобы каждый раз выполнять только наиболее подходящие тесты. Однако, начало – половина дела, и первые шаги уже сделаны.

Обсудить в форуме