Test JUnit con numero dinamico di test


95

Nel nostro progetto ho diversi test JUnit che, ad esempio, prendono ogni file da una directory ed eseguono un test su di esso. Se implemento un testEveryFileInDirectorymetodo in TestCasequesto si presenta come un solo test che potrebbe fallire o avere successo. Ma sono interessato ai risultati su ogni singolo file. Come posso scrivere un TestCase/ in modo TestSuitetale che ogni file venga visualizzato come un test separato, ad esempio nel TestRunner grafico di Eclipse? (Codificare un metodo di test esplicito per ogni file non è un'opzione.)

Confronta anche la domanda ParameterizedTest con un nome in Eclipse Testrunner .


Risposte:


102

Dai un'occhiata ai test parametrizzati in JUnit 4.

In realtà l'ho fatto pochi giorni fa. Proverò a spiegare ...

Per prima cosa costruisci la tua classe di test normalmente, dato che ti limiti a testare con un file di input. Decora la tua classe con:

@RunWith(Parameterized.class)

Crea un costruttore che prenda l'input che cambierà in ogni chiamata di test (in questo caso potrebbe essere il file stesso)

Quindi, crea un metodo statico che restituirà un Collectionof array. Ogni array nella raccolta conterrà gli argomenti di input per il costruttore della classe, ad esempio il file. Decora questo metodo con:

@Parameters

Ecco un esempio di classe.

@RunWith(Parameterized.class)
public class ParameterizedTest {

    private File file;

    public ParameterizedTest(File file) {
        this.file = file;
    }

    @Test
    public void test1() throws Exception {  }

    @Test
    public void test2() throws Exception {  }

    @Parameters
    public static Collection<Object[]> data() {
        // load the files as you want
        Object[] fileArg1 = new Object[] { new File("path1") };
        Object[] fileArg2 = new Object[] { new File("path2") };

        Collection<Object[]> data = new ArrayList<Object[]>();
        data.add(fileArg1);
        data.add(fileArg2);
        return data;
    }
}

Controlla anche questo esempio


1
Grazie! Il metodo JUnit 4 è migliore del metodo JUnit 3 fornito in un'altra risposta, poiché JUnit 3 confonde il test runner di eclissi e con il metodo JUnit 4 puoi rieseguire i test ecc. Mi chiedo solo come posso far mostrare eclipse a nome per il test - mostra solo [0], [1] ecc.
Hans-Peter Störr

@hstoerr, sembra che questo sarà nella prossima versione di JUnit :-) github.com/KentBeck/junit/commit/…
rescdsk

Come lo trasformereste se voleste che ogni esecuzione [con una diversa combinazione di dati] modifichi il nome di questa esecuzione di prova? [Vale a dire il file Path1 verrebbe testato come: test1Path1, test2Path?
monaco


27

JUnità 3

public class XTest extends TestCase {

    public File file;

    public XTest(File file) {
        super(file.toString());
        this.file = file;
    }

    public void testX() {
        fail("Failed: " + file);
    }

}

public class XTestSuite extends TestSuite {

    public static Test suite() {
        TestSuite suite = new TestSuite("XTestSuite");
        File[] files = new File(".").listFiles();
        for (File file : files) {
            suite.addTest(new XTest(file));
        }
        return suite;
    }

}

JUnit 4

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class TestY {

    @Parameters
    public static Collection<Object[]> getFiles() {
        Collection<Object[]> params = new ArrayList<Object[]>();
        for (File f : new File(".").listFiles()) {
            Object[] arr = new Object[] { f };
            params.add(arr);
        }
        return params;
    }

    private File file;

    public TestY(File file) {
        this.file = file;
    }

    @Test
    public void testY() {
        fail(file.toString());
    }

}

11

Giugno 5 test parametrizzati

I test parametrizzati JUnit 5 supportano ciò consentendo l'uso di un metodo come origine dati :

@ParameterizedTest
@MethodSource("fileProvider")
void testFile(File f) {
    // Your test comes here
}

static Stream<File> fileProvider() {
    return Arrays.asList(new File(".").list()).stream();
}

JUnit 5 DynamicTests

JUnit 5 supporta questo anche attraverso la nozione di a DynamicTest, che deve essere generata in a @TestFactory, mediante il metodo statico dynamicTest.

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.stream.Stream;

@TestFactory
public Stream<DynamicTest> testFiles() {
    return Arrays.asList(new File(".").list())
            .stream()
            .map((file) -> dynamicTest(
                    "Test for file: " + file,
                    () -> { /* Your test comes here */ }));
}

I test eseguiti nel tuo IDE (IntelliJ qui) verranno visualizzati in questo modo:

Uscita in IntelliJ


3

Dovrebbe essere possibile in JUnit 3 ereditando TestSuitee sovrascrivendo il tests()metodo per elencare i file e per ogni restituire un'istanza di una sottoclasse diTestCase che prende il nome del file come parametro del costruttore e ha un metodo di test che verifica il file fornito nel costruttore.

In JUnit 4 potrebbe essere ancora più semplice.


2

Potresti considerare di utilizzare la libreria JUnitParams , quindi avresti alcune opzioni in più (più pulite):

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test1(File file) throws Exception {  }

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test2(File file) throws Exception {  }

    public static File[] data() {
        return new File[] { new File("path1"), new File("path2") };
    }
}

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test1(String path) throws Exception {
        File file = new File(path);
    }

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test2(String path) throws Exception {
        File file = new File(path);
    }
}

Puoi vedere altri esempi di utilizzo qui .

Oltre a JUnitParams, perché scrivere test parametrizzati con esso è più facile e più leggibile :

Il progetto JUnitParams aggiunge un nuovo runner a JUnit e fornisce test parametrizzati molto più facili e leggibili per JUnit> = 4.6.

Principali differenze rispetto allo standard JUnit Parametrised runner:

  • più esplicito: i parametri sono nei parametri del metodo di test, non nei campi di classe
  • meno codice: non è necessario un costruttore per impostare i parametri
  • puoi mescolare metodi parametrizzati con metodi non parametrizzati in una classe
  • params può essere passato come stringa CSV o da una classe di provider di parametri
  • La classe provider di parametri può avere tutti i parametri che forniscono i metodi desiderati, in modo da poter raggruppare casi diversi
  • puoi avere un metodo di test che fornisce parametri (niente più classi esterne o statiche)
  • puoi vedere i valori dei parametri effettivi nel tuo IDE (in Parametrised di JUnit sono solo numeri consecutivi di parametri)

1

Se TestNG è un'opzione, è possibile utilizzare Parameters con DataProvider .

Il test di ogni singolo file avrà il suo risultato mostrato nel report basato su testo o nell'interfaccia utente del plugin TestNG di Eclipse. Il numero di test totali eseguiti conterà ciascuno dei tuoi file individualmente.

Questo comportamento differisce dalle teorie di JUnit , in cui tutti i risultati sono raggruppati in un'unica voce "teoria" e contano solo come 1 test. Se desideri rapporti separati sui risultati in JUnit, puoi provare i test parametrizzati .

Test e input

public class FileTest {

    @DataProvider(name="files")
    public File[][] getFiles(){
        return new File[][] {
            { new File("file1") },
            { new File("file2") }
        };
        // or scan a directory
    }

    @Test(dataProvider="files")
    public void testFile(File file){
        //run tests on file
    }
}

Output di esempio

PASSED: testFile(file1)
PASSED: testFile(file2)

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

Non conosco teorie, ma i test parametrizzati in JUnit sono mostrati separatamente in eclipse, non raggruppati insieme.
Hans-Peter Störr

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.