Mutation testing на примере Pitest.Источник: habrahabr
В байт-код ваших классов внедряются случайные изменения, иначе называемые мутациями. Если после такой мутации не упал ни один тест, который покрывает внесённые изменения, то велика вероятность того, что с тестами у вас не особо-то и хорошо. Пример возможной мутации: Изменение довольно критичное, потому тест, покрывающий этот блок кода, наверняка должен упасть. Под катом я расскажу о весьма хорошей библиотеке pitest, покажу, как её подключить к своему проекту, и приведу результаты тестирования на реальном коде. Простенький проект.Начнём с простого проекта[github], содержащего один-единственный класс: и тест на него:
Чтобы подключить pitest, достаточно добавить его плагин в maven:
Чуть подробнее по конфигурации: inScopeClasses определяет те классы, в которых следует искать тесты и классы, которые следует подвергать мутации. Target Classes определяет те классы, которые следует подвергнуть только мутации. Кроме того, есть ещё некоторые опции, полный список которых можно посмотреть тут. Если вы по какой-то причине не используете maven, то ещё не всё пропало: можно пользоваться и из командной строки, руководство доступно тут. А чтобы обрести счастье, используя maven, достаточно выполнить команду: mvn org.pitest:pitest-maven:mutation Coverage Понимание отчётов.В результате проверки мы получим довольно-таки большую простыню логов. Читать её не особо удобно, но зато в папке target/pit-reports/%TIMESTAMP% генерируется и html-отчёт, похожий на code coverage. В нашем случае интересная его часть будет выглядеть примерно так:
Цифра три возле строки 14 тут означает, сколько мутаций было к этой строчке применено. Далее в разделе mutations для каждой строчки описывается, какие были применены мутации, и каков был результат. Результат выполнения мутации.KILLED - в результате мутации упали все тесты, проверяющие эту строку. Можно заметить, что у нас все мутации имеют такой статус, что довольно хорошо. Типы мутаций.На данный момент есть всего 11 мутаций. Зелёным выделены те, которые включены по умолчанию. Детальное описание различных типов мутаций доступно на официальном сайте. Усложняем пример.Получается, что в нашем sample-проекте мутации были в условии (2 шт) и в возвращаемом значении. Попробуем теперь добиться большего количества мутаций. Перепишем сам класс так: Но вот в тестах новую функциональность тестировать не будем: При запуске code coverage никаких проблем выявлено не будет. А вот если мы запустим mutation testing, то нас быстро схватят за руку и скажут: а функциональность-то не протестирована! Успех! Теперь мы довольно точно можем сказать, какой код действительно протестирован, а какой нет, и всякие "якобы" тесты, которые на самом деле ничего не проверяют, быстро будут обнаружены. Почему именно pitest?Идея мутационного тестирования, вообще говоря, не нова, и несколько библиотек уже существовало. Наиболее примечательные из них - Javalanche и Jumble. Однако и они, и другие библиотеки не особо активно развиваются, некоторые из них тормозны и глючны, и практически не имеют интеграции с системами сборки и другими библиотеками. Подробное сравнение доступно тут. Проверим на реальном проекте.Для пущей интересности правильно было бы на каком-нибудь реальном проекте продемонстрировать, как mutation testing находит проблемы, которые не находит code coverage. Отлично для этого подойдёт cobertura - утилита, считающая code coverage. Её отчёт может быть найден в полном виде тут, а я приведу лишь маленький кусочек. Чтобы его получить, пришлось немного попотеть с добавлением поддержки maven в исходники и подождать минут двадцать, пока будет идти мутационное тестирование.. Результат получился таким. Cobertura показывает, что всё хорошо: Pitest срывает покровы: Итого.Итого, подход классный, и явно гораздо более точно оценивает качество тестов, чем code coverage. Конечно, такие проверки и работают существенно дольше, чем обычный coverage, и потому на больших проектах могут занимать часы. Кроме того, сама библиотека Pitest пока несколько сыровата. Например, нет возможности проводить тестирование в несколько потоков, или обязательно успешное выполнение всех тестов без мутаций. Проект, впрочем, opensource, и весьма активно развивается, так что я полагаю, что через какое-то время можно будет начать думать о том, чтобы использовать его всерьёз. |