Ricerca…


Osservazioni

Parametro Contesto Dettagli
@Prima della lezione Statico Eseguito quando la classe viene creata per la prima volta
@Prima Esempio Eseguito prima di ogni test della classe
@Test Esempio Dovrebbe essere dichiarato ogni metodo da testare
@Dopo Esempio Eseguito dopo ogni test della classe
@Dopo la lezione Statico Eseguito prima della distruzione della classe

Esempio di formato della classe di test

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() {}
    
    }
}

Test delle unità usando JUnit

Qui abbiamo un Counter classe con metodi countNumbers() e 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.*");
    }
}

Per testare questa classe, possiamo usare il framework Junit. Aggiungi junit.jar nel tuo percorso di classe del progetto. Quindi creare la classe Test case come di seguito:

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);
    }
}

Nel tuo IDE puoi eseguire questa classe come "Junit testcase" e vedere l'output nella GUI. Nel prompt dei comandi è possibile compilare ed eseguire il test case come di seguito:

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

L'output di una prova di successo dovrebbe essere simile a:

JUnit version 4.9b2
..
Time: 0.019

OK (2 tests)

Nel caso di un fallimento del test, sembrerebbe più simile a:

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

infissi

Da Wikipedia :

Un dispositivo di prova è usato per testare costantemente un oggetto, un dispositivo o un pezzo di software.

Può anche migliorare la leggibilità dei test estraendo codice di inizializzazione / finalizzazione comune dai metodi di test stessi.

Nei casi in cui l'inizializzazione comune può essere eseguita una volta anziché prima di ogni test, ciò può anche ridurre il tempo necessario per eseguire i test.

L'esempio seguente è ideato per mostrare le opzioni principali fornite da JUnit. Assumi una classe Foo che è costosa da inizializzare:

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

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

Un altro Bar classe ha un riferimento a Foo :

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

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

I test sottostanti prevedono un contesto iniziale di un elenco contenente una singola 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();
    }
}

Nell'esempio il metodo annotato @BeforeClass setupOnce() viene utilizzato per creare l'oggetto Foo , che è costoso da inizializzare. È importante che non venga modificato da nessuno dei test, altrimenti l'esito dell'esecuzione del test potrebbe dipendere dall'ordine di esecuzione dei singoli test. L'idea è che ogni test sia indipendente e testa una piccola caratteristica.

L' setup() metodo @Before annotated setup() imposta il contesto di test. Il contesto può essere modificato durante l'esecuzione del test, motivo per cui deve essere inizializzato prima di ogni test. L'effetto equivalente potrebbe essere raggiunto includendo il codice contenuto in questo metodo all'inizio di ciascun metodo di prova.

Il metodo annotato @After tearDown() pulisce le risorse all'interno del contesto di test. Viene chiamato dopo ogni richiamo di test, e come tale viene spesso utilizzato per liberare risorse allocate in un metodo @Before annotato.

Il metodo annotato @AfterClass tearDownOnce() ripulisce le risorse una volta eseguiti tutti i test. Tali metodi vengono in genere utilizzati per liberare risorse allocate durante l'inizializzazione o in un metodo annotato @BeforeClass . Detto questo, è probabilmente meglio evitare le risorse esterne nei test unitari in modo che i test non dipendano da nulla al di fuori della classe di test.

Test delle unità usando le teorie

Da JavaDoc

The Theories runner consente di testare una determinata funzionalità rispetto a un sottoinsieme di un insieme infinito di punti dati.

Teorie correnti

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
    }
}

I metodi annotati con @Theory verranno letti come teorie da Teorie runner.

@DataPoint annotation

@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
    }
}

Ogni campo annotato con @DataPoint verrà utilizzato come parametro di metodo di un determinato tipo nelle teorie. Nell'esempio sopra theoryMethod verrà eseguito due volte con i seguenti parametri: ["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
    }
}

Ogni elemento dell'array annotato con @DataPoints annotazione @DataPoints verrà utilizzato come parametro di metodo di un determinato tipo nelle teorie. Nell'esempio sopra theoryMethod verrà eseguito quattro volte con i seguenti parametri: ["str1", 1], ["str2", 1], ["str1", 2], ["str2", 2]

Valutazione della prestazione

Se è necessario verificare se il metodo di test impiega troppo tempo per essere eseguito, è possibile farlo menzionando il tempo di esecuzione previsto utilizzando la proprietà timeout dell'annotazione @Test. Se l'esecuzione del test richiede più tempo di quel numero di millisecondi, si verifica un errore nel metodo di prova.

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());
    }

}

Nella maggior parte dei casi senza il testString riscaldamento JVM, testString fallirà. Ma testStringBuffer e testStringBuilder dovrebbero superare questo test con successo.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow