Recherche…


Remarques

Paramètre Le contexte Détails
@Avant les cours Statique Exécuté lors de la création de la classe
@Avant Exemple Exécuté avant chaque test dans la classe
@Tester Exemple Devrait être déclaré chaque méthode pour tester
@Après Exemple Exécuté après chaque test dans la classe
@Après les cours Statique Exécuté avant la destruction de la classe

Exemple de format de classe de 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() {}
    
    }
}

Tests unitaires avec JUnit

Nous avons ici une classe Counter avec les méthodes countNumbers() et 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.*");
    }
}

Pour tester cette classe, nous pouvons utiliser le framework Junit. Ajoutez le junit.jar dans votre chemin de classe de projet. Puis créez la classe de cas de test comme ci-dessous:

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

Dans votre IDE, vous pouvez exécuter cette classe en tant que "test de Junit" et voir la sortie dans l'interface graphique. Dans l'invite de commande, vous pouvez compiler et exécuter le scénario de test comme suit:

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

La sortie d'un test réussi doit ressembler à:

JUnit version 4.9b2
..
Time: 0.019

OK (2 tests)

Dans le cas d'un échec de test, cela ressemblerait davantage à:

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

Agencements

De Wikipedia :

Un dispositif de test est utilisé pour tester de manière cohérente un élément, un périphérique ou un logiciel.

Il peut également améliorer la lisibilité des tests en extrayant le code d'initialisation / finalisation commun des méthodes de test elles-mêmes.

Lorsque l'initialisation commune peut être exécutée une fois au lieu de chaque test, cela peut également réduire le temps nécessaire à l'exécution des tests.

L'exemple ci-dessous est conçu pour afficher les principales options fournies par JUnit. Supposons une classe Foo qui coûte cher à initialiser:

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

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

Une autre classe Bar a une référence à Foo :

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

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

Les tests ci-dessous attendent un contexte initial d'une liste contenant une seule 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();
    }
}

Dans l'exemple de la @BeforeClass méthode annotée setupOnce() est utilisée pour créer le Foo objet, ce qui est coûteux pour initialiser. Il est important qu’il ne soit modifié par aucun des tests, sinon le résultat du test pourrait dépendre de l’ordre d’exécution des tests individuels. L'idée est que chaque test est indépendant et teste une petite fonctionnalité.

La méthode annotée @Before setup() configure le contexte de test. Le contexte peut être modifié pendant l'exécution du test, c'est pourquoi il doit être initialisé avant chaque test. L'effet équivalent pourrait être obtenu en incluant le code contenu dans cette méthode au début de chaque méthode de test.

La méthode annotée @After tearDown() nettoie les ressources dans le contexte de test. Il est appelé après chaque appel de test et, en tant que tel, est souvent utilisé pour libérer des ressources allouées dans une méthode annotée @Before .

La méthode annotée @AfterClass tearDownOnce() nettoie les ressources une fois que tous les tests ont été exécutés. De telles méthodes sont généralement utilisées pour libérer des ressources allouées lors de l'initialisation ou dans une méthode annotée @BeforeClass . Cela dit, il est probablement préférable d'éviter les ressources externes dans les tests unitaires afin que les tests ne dépendent pas de la classe de test.

Tests unitaires utilisant des théories

De JavaDoc

Le runner Theories permet de tester une fonctionnalité donnée sur un sous-ensemble d'un ensemble infini de points de données.

Théories courantes

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

Les méthodes annotées avec @Theory seront lues comme des théories par coureur de Theories.

Annotation @DataPoint

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

Chaque champ annoté avec @DataPoint sera utilisé comme paramètre de méthode d'un type donné dans les théories. Dans example ci-dessus, theoryMethod sera exécuté deux fois avec les paramètres suivants: ["str1", 2] , ["str2", 2]

@DataPoints annotation @RunWith (Theories.class) classe publique 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
    }
}

Chaque élément du tableau annoté avec @DataPoints annotation @DataPoints sera utilisé comme paramètre de méthode d'un type donné dans les théories. Dans example ci-dessus, theoryMethod sera exécuté quatre fois avec les paramètres suivants: ["str1", 1], ["str2", 1], ["str1", 2], ["str2", 2]

Mesure du rendement

Si vous avez besoin de vérifier si votre méthode de test prend trop de temps à exécuter, vous pouvez le faire en mentionnant votre temps d'exécution attendu en utilisant la propriété timeout de l'annotation @Test. Si l'exécution du test prend plus de temps que ce nombre de millisecondes, une méthode de test échoue.

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

}

Dans la plupart des cas, sans testString JVM, la testString échouera. Mais testStringBuffer et testStringBuilder doivent réussir ce test.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow