1. Общ преглед
Тестването на софтуер се отнася до техниките, използвани за оценка на функционалността на софтуерно приложение. В тази статия ще обсъдим някои от показателите, използвани в индустрията за тестване на софтуер, като покритие на кода и тестване на мутации , със особен интерес за това как да извършим тест за мутация с помощта на библиотеката PITest .
За по-голяма простота ще базираме тази демонстрация на основна функция на палиндрома - Имайте предвид, че палиндромът е низ, който чете еднакво назад и напред.
2. Зависимости на Maven
Както можете да видите в конфигурацията на зависимостите на Maven, ние ще използваме JUnit, за да стартираме нашите тестове, и библиотеката PITest, за да въведем мутанти в нашия код - не се притеснявайте, ще видим след секунда какво е мутант. Винаги можете да потърсите най-новата версия на зависимостта спрямо централното хранилище на maven, като следвате тази връзка.
org.pitest pitest-parent 1.1.10 pom
За да може библиотеката PITest да работи и работи, ние също трябва да включим приставката pitest-maven в нашия конфигурационен файл pom.xml :
org.pitest pitest-maven 1.1.10 com.baeldung.testing.mutation.* com.baeldung.mutation.test.*
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 за повече подробности относно създадените мутанти:

Това са мутаторите, активни по подразбиране при изпълнение на тест за покритие на мутация:
- 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 , за да дефинираме списъка с класове, които трябва да се мутират. Мутационното тестване не може да се приложи към всички класове в реалния световен проект, тъй като ще отнеме много време и ще е от решаващо значение за ресурсите.
Също така е важно да определите мутаторите, които планирате да използвате по време на тестване на мутации, за да сведете до минимум изчислителните ресурси, необходими за извършване на тестовете:
com.baeldung.testing.mutation.* com.baeldung.mutation.test.* CONSTRUCTOR_CALLS VOID_METHOD_CALLS RETURN_VALS NON_VOID_METHOD_CALLS
Освен това библиотеката PITest предлага разнообразни опции, които са на разположение за персонализиране на вашите стратегии за тестване , можете да посочите максималния брой мутанти, въведени от класа, като използвате опцията maxMutationsPerClass например. Повече подробности за опциите PITest в официалното ръководство за бърз старт на Maven .
8. Заключение
Имайте предвид, че покритието на кода все още е важна метрика, но понякога не е достатъчно, за да гарантира добре тестван код. Така че в тази статия сме преминали през тестване на мутации като по-сложен начин да гарантираме качеството на тестовете и да подкрепим тестови случаи, използвайки библиотеката PITest .
Видяхме също как да анализираме основни доклади PITest, като същевременно подобряваме оценката за покритие на мутацията .
Въпреки че тестването на мутации разкрива дефекти в кода, той трябва да се използва разумно, защото това е изключително скъп и отнемащ време процес .
Можете да разгледате примерите, предоставени в тази статия в свързания проект GitHub .