Troška teórie na začiatok
Mutačné testovanie (alebo tiež analýza mutácií) sa používa pri návrhoch nových testov v agilnom procese vývoja softvéru. Vyhodnocuje sa nimi kvalita existujúcich Unit testov. Mutačné testovanie vyvoláva zmenu testovaného kódu, tzv. mutácie. Každá zmutovaná verzia kódu sa nazýva mutant a testy, ktoré majú za úlohu odhaliť mutantov tým, že odhalia odlišné správanie zmutovaného kódu od pôvodnej-originálnej verzie sa nazýva zabíjanie mutantov.
Testovacie suity sú potom merané percentom zabitých mutantov. Nové testy môžu byť navrhnuté aj tak, aby zabíjali ďalších možných mutantov a zároveň odhaľovali tzv. „weak tests“ – slabé testy.
Mutácie kódu sú založené na definovaní tzv. „operátorov mutácie“, ktoré buď napodobňujú typické chyby v programovaní (napríklad použitie zlého operátora alebo názvu premennej), alebo mutáciou vytvoria chyby kódu (ako je napríklad delenie nulou každého výrazu v testovanej metóde). Cieľom je pomôcť testerom a developerom vytvoriť lepšie testy, alebo nájsť nedostatky v testovacích dátach použitých pri testoch.
Krátky priklad
Majme testovaciu Java triedu (Calculator.java)
public class Calculator { int valueDisplayed; public Calculator() { this.valueDisplayed = 0; } public Calculator(final int initialValue) { this.valueDisplayed = initialValue; } public void add(final int x) { this.valueDisplayed += x; } public void subtract(final int x) { this.valueDisplayed -= x; } public void power(final int x) { this.valueDisplayed = (int) Math.pow(this.valueDisplayed, x); } public int getResult() { return this.valueDisplayed; } public void set(final int x) { this.valueDisplayed = x; } public boolean setConditional(final int x, final boolean yesOrNo) { if (yesOrNo) { set(x); return true; } else { return false; } } }
… a k nej asociovanú testovaciu triedu (CalculatorTest.java)
import org.junit.Assert; import org.junit.Test; import Calculator; public class CalculatorTest { @Test public void testAddition() { final Calculator calculator = new Calculator(); calculator.add(2); Assert.assertEquals(calculator.getResult(), 2); } @Test public void testPower() { final Calculator calculator = new Calculator(2); calculator.power(3); Assert.assertEquals(calculator.getResult(), 8); } /* @Test public void testSubtraction() { final Calculator calculator = new Calculator(5); calculator.subtract(4); Assert.assertEquals(calculator.getResult(), 1); } */ @Test public void testConditionalSetTrue() { final Calculator calculator = new Calculator(); Assert.assertEquals(calculator.setConditional(2, true), true); // Assert.assertEquals(calculator.getResult(), 2); } @Test public void testConditionalSetFalse() { final Calculator calculator = new Calculator(); Assert.assertEquals(calculator.setConditional(3, false), false); // Assert.assertEquals(calculator.getResult(), 0); }
Po dokončení testov sa zdá, že je všetko v poriadku. Všetky testy sú „zelené“, čiže v poriadku.
pri dôkladnejšom pohľade ale zistíme, že:
- „Subtraction method“ nie je zahrnutá do testov
- Metóda “setConditional” robí dve operácie súčasne. Nastavuje premennú “valueDisplayed” a jej návratová hodnota je boolean. Nastavenie premennej tiež nie je testom pokryté (weak test)
Ideálny príklad pre test Unit testov použitím mutačného testovania.
Detekcia nepokrytých a weak testov pomocou PIT frameworku
Použitím PIT – real world mutation testing, vývojári majú možnosť rýchlo a ľahko odhaliť „weak test“ a zároveň zobraziť riadky nepokryté unit testom. Pozrime si teda PIT report:
Ako na to? Ako použiť PIT framework v projekte pripravenom pre maven
pom.xml
<build> <plugins> <plugin> <groupId>org.pitest</groupId> <artifactId>pitest-maven</artifactId> <version>1.1.4</version> <configuration> <targetClasses> <param>package.root.containing.classes.to.mutate*</param> </targetClasses> <targetTests> <param>package.root.containing.test.classes*</param> </targetTests> </configuration> </plugin> </plugins> </build>
maven spustíme riadkovým príkazom:
- mvn org.pitest:pitest-maven:mutationCoverage
alebo vytvoríme „run configuration“ v Eclipse:
PIT report potom nájdeme v rámci projektu v adresári /target/pit-reports/<date>/index.html