1. Обзор
Тестирование программного обеспечения относится к методам, используемым для оценки функциональности программного приложения. В этой статье мы собираемся обсудить некоторые метрики, используемые в индустрии тестирования программного обеспечения, такие как охват кода и тестирование мутаций , с особым интересом о том, как выполнить тест на мутацию с использованием http://pitest .org/[ Библиотека PITest ].
Для простоты мы собираемся основывать эту демонстрацию на базовой функции палиндрома - обратите внимание, что палиндром - это строка, которая читает одно и то же назад и вперед.
2. Зависимости Maven
Как вы можете видеть в конфигурации зависимостей Maven, мы будем использовать JUnit для запуска наших тестов и библиотеку PITest для введения мутантов в наш код - не волнуйтесь, через секунду мы увидим, что такое мутант.
Вы всегда можете посмотреть последнюю версию зависимостей в центральном репозитории maven, следуя этой link .
<dependency>
<groupId>org.pitest</groupId>
<artifactId>pitest-parent</artifactId>
<version>1.1.10</version>
<type>pom</type>
</dependency>
Для того чтобы библиотека PITest была запущена и работала, нам также необходимо включить плагин pitest-maven в наш файл конфигурации pom.xml :
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.1.10</version>
<configuration>
<targetClasses>
<param>com.baeldung.testing.mutation.** </param>
</targetClasses>
<targetTests>
<param>com.baeldung.mutation.test.** </param>
</targetTests>
</configuration>
</plugin>
3. Настройка проекта
Теперь, когда мы настроили наши зависимости Maven, давайте посмотрим на эту понятную функцию палиндрома:
public boolean isPalindrome(String inputString) {
if (inputString.length() == 0) {
return true;
} else {
char firstChar = inputString.charAt(0);
char lastChar = inputString.charAt(inputString.length() - 1);
String mid = inputString.substring(1, inputString.length() - 1);
return (firstChar == lastChar) && isPalindrome(mid);
}
}
Все, что нам сейчас нужно, это простой тест JUnit, чтобы убедиться, что наша реализация работает желаемым образом:
@Test
public void whenPalindrom__thenAccept() {
Palindrome palindromeTester = new Palindrome();
assertTrue(palindromeTester.isPalindrome("noon"));
}
Пока все хорошо, мы готовы успешно запустить наш тестовый пример как тест JUnit.
Далее в этой статье мы сосредоточимся на покрытии кода и мутаций с использованием библиотеки PITest.
4. Покрытие кода
Покрытие кода широко использовалось в индустрии программного обеспечения, чтобы измерить, какой процент путей выполнения был использован во время автоматизированных тестов.
Мы можем измерить эффективное покрытие кода на основе путей выполнения, используя такие инструменты, как Eclemma , доступные в Eclipse IDE
После запуска TestPalindrome с покрытием кода мы можем легко достичь 100% оценки покрытия. Обратите внимание, что isPalindrome является рекурсивным, поэтому совершенно очевидно, что проверка длины пустого ввода в любом случае будет выполнена.
К сожалению, метрики покрытия кода иногда могут быть весьма неэффективными , потому что 100% оценка покрытия кода только означает, что все строки были выполнены хотя бы один раз, но это ничего не говорит о точности тестирования или полноте прецедентов , и это почему мутационное тестирование действительно имеет значение.
5. Покрытие мутации
Мутационное тестирование - это метод тестирования, используемый для улучшения адекватности тестов и выявления дефектов в коде. Идея состоит в том, чтобы динамически изменять производственный код и вызывать сбои тестов.
Хорошие тесты не пройдут
Каждое изменение в коде называется мутант , и это приводит к измененной версии программы, называемой мутация .
Мы говорим, что мутация "убита", если она может вызвать сбой в тестах. Мы также говорим, что мутация выжила , если мутант не мог повлиять на поведение тестов.
Теперь давайте запустим тест с использованием Maven с параметром цели, установленным на:
org.pitest: pitest-Maven: mutationCoverage .
Мы можем проверить отчеты в формате HTML в каталоге target/pit-test/YYYYMMDDHHMI :
-
100% покрытие линии: 7/7
-
63% мутации: 5/8
Ясно, что наш тест охватывает все пути выполнения, таким образом, оценка покрытия линии составляет 100%. С другой стороны, библиотека PITest представила 8 мутантов , 5 из них были убиты - вызвано неудачей - но 3 выжили.
Мы можем проверить отчет com.baeldung.testing.mutation/Palindrome.java.html для более подробной информации о созданных мутантах:
ссылка:/uploads/mutations.png%20715w[]
Это мутаторы, активные по умолчанию при запуске теста покрытия мутацией:
-
INCREMENTS MUTATOR__
-
VOID METHOD CALL MUTATOR__
-
RETURN VALS MUTATOR
-
MATH MUTATOR__
-
NEGATE CONDITIONALS MUTATOR
-
INVERT NEGS MUTATOR
-
CONDITIONALS BOUNDARY MUTATOR
Для получения более подробной информации о мутаторах PITest вы можете проверить официальную ссылку страница документации .
Наш показатель охвата мутацией отражает отсутствие тестовых случаев , так как мы не можем гарантировать, что наша функция палиндрома отклоняет непалиндромные и околопалиндромные входные данные.
6. Улучшение показателя мутации
Теперь, когда мы знаем, что такое мутация, нам нужно улучшить наш показатель мутации, убивая выживших мутантов.
Давайте возьмем первую мутацию - отрицательную условную - в строке 6 в качестве примера. Мутант выжил, потому что даже если мы изменим фрагмент кода:
if (inputString.length() == 0) {
return true;
}
Для того, чтобы:
if (inputString.length() != 0) {
return true;
}
Тест пройдет, и поэтому мутация выжила. Идея состоит в том, чтобы внедрить новый тест, который провалится, если будет введен мутант . То же самое можно сделать для остальных мутантов.
@Test
public void whenNotPalindrom__thanReject() {
Palindrome palindromeTester = new Palindrome();
assertFalse(palindromeTester.isPalindrome("box"));
}
@Test
public void whenNearPalindrom__thanReject() {
Palindrome palindromeTester = new Palindrome();
assertFalse(palindromeTester.isPalindrome("neon"));
}
Теперь мы можем запустить наши тесты с помощью плагина покрытия мутаций, чтобы убедиться, что все мутации были уничтожены , как мы видим в отчете PITest, созданном в целевой директории.
-
100% покрытие линии: 7/7
-
100% охват мутации: 8/8
7. Конфигурация тестов PITest
Мутационное тестирование иногда может потребовать значительных ресурсов, поэтому нам необходимо установить правильную конфигурацию для повышения эффективности тестирования. Мы можем использовать тег targetClasses , чтобы определить список классов, которые должны быть изменены. Мутационное тестирование не может быть применено ко всем классам в реальном проекте, так как это потребует много времени и ресурсов.
Также важно определить мутаторы, которые вы планируете использовать во время мутационного тестирования, чтобы минимизировать вычислительные ресурсы, необходимые для выполнения тестов:
<configuration>
<targetClasses>
<param>com.baeldung.testing.mutation.** </param>
</targetClasses>
<targetTests>
<param>com.baeldung.mutation.test.** </param>
</targetTests>
<mutators>
<mutator>CONSTRUCTOR__CALLS</mutator>
<mutator>VOID__METHOD__CALLS</mutator>
<mutator>RETURN__VALS</mutator>
<mutator>NON__VOID__METHOD__CALLS</mutator>
</mutators>
</configuration>
Более того, библиотека PITest предлагает множество опций, доступных для настройки ваших стратегий тестирования , вы можете указать максимальное количество мутантов, представленных классом, используя, например, параметр maxMutationsPerClass . Подробнее о параметрах PITest можно узнать в официальном руководстве по быстрому запуску Maven .
8. Заключение
Обратите внимание, что охват кода все еще является важной метрикой, но иногда этого недостаточно, чтобы гарантировать хорошо протестированный код. Поэтому в этой статье мы рассмотрели тестирование на мутации как более сложный способ обеспечения качества тестов и подтверждения тестовых случаев с использованием библиотеки PITest .
Мы также увидели, как анализировать базовые отчеты PITest, улучшая показатель охвата мутациями .
Несмотря на то, что мутационное тестирование выявляет дефекты в коде, его следует использовать с умом, потому что это чрезвычайно дорогой и длительный процесс .
Вы можете ознакомиться с примерами, представленными в этой статье, в связанном GitHub проекте .