Agile QA – Zabíjaním mutantov testujeme Unit testy (Java)

204

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

Dobrý článok? Chceš dostávať ďalšie?

Už viac ako 4 200 z vás dostáva správy e-mailom. Nemusíš sa báť, nie každé ráno. Len občasne.

Tvoj email neposkytneme 3tím stranám. Posielame naňho len informácie z robime.it. Kedykoľvek sa môžete odhlásiť.