Sök…


Anmärkningar

Parameter Sammanhang detaljer
@Innan lektionen Statisk Körs när klassen skapades första gången
@Innan Exempel Utförs före varje test i klassen
@Testa Exempel Bör förklaras varje metod att testa
@Efter Exempel Utförs efter varje test i klassen
@Efter lektionen Statisk Utförd innan klassens förstörelse

Exempel Testklassformat

public class TestFeatureA {

    @BeforeClass
    public static void setupClass() {}
    
    @Before
    public void setupTest() {}
    
    @Test
    public void testA() {}
    
    @Test
    public void testB() {}
    
    @After
    public void tearDownTest() {}
    
    @AfterClass
    public static void tearDownClass() {}
    
    }
}

Enhetstestning med JUnit

Här har vi en Counter med metoderna countNumbers() och hasNumbers() .

public class Counter {

    /* To count the numbers in the input */
    public static int countNumbers(String input) {
        int count = 0;
        for (char letter : input.toCharArray()) {
            if (Character.isDigit(letter))
                count++;
        }
        return count;
    }

    /* To check whether the input has number*/
    public static boolean hasNumber(String input) {
        return input.matches(".*\\d.*");
    }
}

För att testa den här klassen kan vi använda Junit-ramverket. Lägg till junit.jar i din projektklassväg. Skapa sedan testfallsklassen enligt nedan:

import org.junit.Assert; // imports from the junit.jar
import org.junit.Test;

public class CounterTest {

    @Test // Test annotation makes this method as a test case
    public void countNumbersTest() {
        int expectedCount = 3;
        int actualCount = Counter.countNumbers("Hi 123");
        Assert.assertEquals(expectedCount, actualCount); //compares expected and actual value
    }

    @Test
    public void hasNumberTest() {
        boolean expectedValue = false;
        boolean actualValue = Counter.hasNumber("Hi there!");
        Assert.assertEquals(expectedValue, actualValue);
    }
}

I din IDE kan du köra denna klass som "Junit testcase" och se utgången i GUI. I kommandotolken kan du kompilera och köra testfallet enligt nedan:

\> javac -cp ,;junit.jar CounterTest.java
\> java  -cp .;junit.jar org.junit.runner.JUnitCore CounterTest

Produktionen från en framgångsrik testkörning ska se ut som:

JUnit version 4.9b2
..
Time: 0.019

OK (2 tests)

Vid testfel ser det mer ut som:

Time: 0.024
There was 1 failure:
1) CountNumbersTest(CounterTest)
java.lang.AssertionError: expected:<30> but was:<3>
... // truncated output
FAILURES!!!
Tests run: 2,  Failures: 1

fixturer

Från Wikipedia :

En testfixtur är något som används för att konsekvent testa någon artikel, enhet eller programvara.

Det kan också förbättra läsbarheten för tester genom att extrahera vanlig initialisering / slutföringskod från själva testmetoderna.

Där vanliga initialiseringar kan utföras en gång i stället för före varje test, kan detta också minska den tid det tar att köra tester.

Exemplet nedan är avsedd för att visa de viktigaste alternativen som tillhandahålls av JUnit. Anta en Foo klass som är dyr att initialisera:

public class Foo {
    public Foo() {
        // expensive initialization
    }

    public void cleanUp() {
        // cleans up resources
    }
}

En annan Bar har en referens till Foo :

public class Bar {
    private Foo foo;
    
    public Bar(Foo foo) {
        this.foo = foo;
    }

    public void cleanUp() {
        // cleans up resources
    }
}

Testerna nedan förväntar sig ett initialt sammanhang för en lista som innehåller en enda Bar .

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class FixturesTest {
    
    private static Foo referenceFoo;
    
    private List<Bar> testContext;
    
    @BeforeClass
    public static void setupOnce() {
        // Called once before any tests have run
        referenceFoo = new Foo();
    }

    @Before
    public void setup() {
        // Called before each test is run
        testContext = Arrays.asList(new Bar(referenceFoo));
    }
    
    @Test
    public void testSingle() {
        assertEquals("Wrong test context size", 1, testContext.size());
        Bar baz = testContext.get(0);
        assertEquals(referenceFoo, baz.getFoo());
    }
    
    @Test
    public void testMultiple() {
        testContext.add(new Bar(referenceFoo));
        assertEquals("Wrong test context size", 2, testContext.size());
        for (Bar baz : testContext) {
            assertEquals(referenceFoo, baz.getFoo());
        }
    }
    
    @After
    public void tearDown() {
        // Called after each test is run
        for (Bar baz : testContext) {
            baz.cleanUp();
        }
    }
    
    @AfterClass
    public void tearDownOnce() {
        // Called once after all tests have run
        referenceFoo.cleanUp();
    }
}

I exemplet används @BeforeClass antecknade metoden setupOnce() för att skapa Foo objektet, vilket är dyrt att initiera. Det är viktigt att det inte modifieras av någon av testerna, annars kan resultatet av testkörningen bero på ordningen för utförandet av de enskilda testerna. Tanken är att varje test är oberoende och testar en liten funktion.

@Before annoterad @Before setup() ställer in testsammansättningen. Kontextet kan ändras under testutförandet, varför det måste initieras före varje test. Den ekvivalenta effekten kan uppnås genom att inkludera koden i denna metod i början av varje testmetod.

@After antecknade metoden tearDown() rensar upp resurser inom testsammanhanget. Det kallas efter varje testanrop, och används som sådan för att frigöra resurser tilldelade i en @Before annoterad metod.

@AfterClass antecknade metoden tearDownOnce() rensar upp resurser när alla tester har körts. Sådana metoder används vanligtvis för att frigöra resurser tilldelade under initialisering eller i en @BeforeClass annoterad metod. Som sagt är det förmodligen bäst att undvika externa resurser i enhetstester så att testerna inte beror på något utanför testklassen.

Enhetstest med teorier

Från JavaDoc

Teoriköraren tillåter att testa en viss funktionalitet mot en delmängd av en oändlig uppsättning datapunkter.

Kör teorier

import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

@RunWith(Theories.class)
public class FixturesTest {

    @Theory
    public void theory(){
        //...some asserts
    }
}

Metoder som anmälts med @Theory kommer att läsas som teorier av Theories löpare.

@DataPoint-kommentar

@RunWith(Theories.class)
public class FixturesTest {

    @DataPoint
    public static String dataPoint1 = "str1";
    @DataPoint
    public static String dataPoint2 = "str2";
    @DataPoint
    public static int intDataPoint = 2;

    @Theory
    public void theoryMethod(String dataPoint, int intData){
        //...some asserts
    }
}

Varje fält som är antecknat med @DataPoint kommer att användas som en metodparameter av en viss typ i teorierna. I exemplet ovan kommer theoryMethod att köras två gånger med följande parametrar: ["str1", 2] , ["str2", 2]

@DataPoints annotation @RunWith (Theories.class) public class FixturesTest {

    @DataPoints
    public static String[] dataPoints = new String[]{"str1", "str2"};
    @DataPoints
    public static int[] dataPoints = new int[]{1, 2};

    @Theory
    public void theoryMethod(String dataPoint, ){
        //...some asserts
    }
}

Varje element i matrisen som antecknas med @DataPoints kommer att användas som en metodparameter av en given typ i teorierna. I exemplet ovan kommer theoryMethod att köras fyra gånger med följande parametrar: ["str1", 1], ["str2", 1], ["str1", 2], ["str2", 2]

Prestandamätning

Om du behöver kontrollera om din testmetod tar för lång tid att utföra kan du göra det genom att nämna din förväntade körningstid med timeout-egenskapen för @Test-annotation. Om testutförandet tar längre tid än det antalet millisekunder gör det att en testmetod misslyckas.

public class StringConcatenationTest {

    private static final int TIMES = 10_000;
    
    // timeout in milliseconds
    @Test(timeout = 20)
    public void testString(){

        String res = "";

        for (int i = 0; i < TIMES; i++) {
            res += i;
        }

        System.out.println(res.length());
    }

    @Test(timeout = 20)
    public void testStringBuilder(){

        StringBuilder res = new StringBuilder();

        for (int i = 0; i < TIMES; i++) {
            res.append(i);
        }

        System.out.println(res.length());
    }

    @Test(timeout = 20)
    public void testStringBuffer(){

        StringBuffer res = new StringBufferr();

        for (int i = 0; i < TIMES; i++) {
            res.append(i);
        }

        System.out.println(res.length());
    }

}

I de flesta fall kommer inte JVM- testString att misslyckas. Men testStringBuffer och testStringBuilder borde klara det här testet framgångsrikt.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow