JUnit-Test mit dynamischer Anzahl von Tests


95

In unserem Projekt habe ich mehrere JUnit- Tests, die z. B. jede Datei aus einem Verzeichnis entnehmen und einen Test darauf ausführen. Wenn ich eine testEveryFileInDirectoryMethode implementiere, wird TestCasedies als nur ein Test angezeigt, der fehlschlagen oder erfolgreich sein kann. Aber ich interessiere mich für die Ergebnisse jeder einzelnen Datei. Wie kann ich ein TestCase/ TestSuiteso schreiben, dass jede Datei als separater Test angezeigt wird, z. B. im grafischen TestRunner von Eclipse? (Das Codieren einer expliziten Testmethode für jede Datei ist keine Option.)

Vergleichen Sie auch die Frage ParameterizedTest mit einem Namen in Eclipse Testrunner .


Antworten:


102

Schauen Sie sich parametrisierte Tests in JUnit 4 an.

Eigentlich habe ich das vor ein paar Tagen gemacht. Ich werde versuchen zu erklären ...

Erstellen Sie zuerst Ihre Testklasse normal, da Sie nur mit einer Eingabedatei testen. Dekorieren Sie Ihre Klasse mit:

@RunWith(Parameterized.class)

Erstellen Sie einen Konstruktor, der die Eingabe übernimmt, die sich bei jedem Testaufruf ändert (in diesem Fall kann es sich um die Datei selbst handeln).

Erstellen Sie dann eine statische Methode, die ein CollectionArray zurückgibt. Jedes Array in der Auflistung enthält die Eingabeargumente für Ihren Klassenkonstruktor, z. B. die Datei. Dekorieren Sie diese Methode mit:

@Parameters

Hier ist eine Beispielklasse.

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

Überprüfen Sie auch dieses Beispiel


1
Vielen Dank! Die JUnit 4-Methode ist besser als die in einer anderen Antwort angegebene JUnit 3-Methode, da die JUnit 3-Methode den Eclipse-Testläufer verwirrt und Sie mit der JUnit 4-Methode die Tests usw. erneut ausführen können. Ich frage mich nur, wie ich Eclipse a anzeigen lassen kann Name für den Test - es zeigt nur [0], [1] usw.
Hans-Peter Störr

@hstoerr, sieht so aus, als ob dies in der nächsten Version von JUnit sein wird :-) github.com/KentBeck/junit/commit/…
residdsk

Wie würden Sie dies transformieren, wenn Sie möchten, dass jeder Lauf [mit einer anderen Datenkombination] den Namen dieses Testlaufs ändert? [Dh Path1-Datei würde getestet werden als: test1Path1, test2Path?
Mönch


27

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

}

Einheit 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

Junit 5 Parametrisierte Tests

Parametrisierte JUnit 5- Tests unterstützen dies, indem sie die Verwendung einer Methode als Datenquelle ermöglichen :

@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 unterstützt dies auch durch den Begriff a DynamicTest, der in a @TestFactorymittels der statischen Methode erzeugt werden soll 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 */ }));
}

Die in Ihrer IDE (IntelliJ hier) ausgeführten Tests werden folgendermaßen angezeigt:

Ausgabe in IntelliJ


3

Sollte in JUnit 3 möglich sein, indem TestSuitedie tests()Methode zum Auflisten der Dateien geerbt und überschrieben wird und für jede Rückgabe eine Instanz einer Unterklasse vonTestCase den Dateinamen als Konstruktorparameter verwendet und über eine Testmethode verfügt, die die im Konstruktor angegebene Datei testet.

In JUnit 4 könnte es noch einfacher sein.


2

Sie könnten die Verwendung der JUnitParams-Bibliothek in Betracht ziehen , damit Sie einige weitere (sauberere) Optionen haben:

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

Weitere Anwendungsbeispiele finden Sie hier .

Darüber hinaus ist es einfacher und lesbarer, JUnitParams mit parametrisierten Tests zu schreiben :

Das JUnitParams-Projekt fügt JUnit einen neuen Runner hinzu und bietet viel einfachere und lesbarere parametrisierte Tests für JUnit> = 4.6.

Hauptunterschiede zum standardmäßigen JUnit Parametrised Runner:

  • expliziter - Parameter befinden sich in Testmethodenparametern, nicht in Klassenfeldern
  • weniger Code - Sie benötigen keinen Konstruktor, um Parameter einzurichten
  • Sie können parametrisierte mit nicht parametrisierten Methoden in einer Klasse mischen
  • Parameter können als CSV-Zeichenfolge oder von einer Parameteranbieterklasse übergeben werden
  • Die Parameteranbieterklasse kann so viele Parameter enthalten, die Methoden bereitstellen, wie Sie möchten, sodass Sie verschiedene Fälle gruppieren können
  • Sie können eine Testmethode verwenden, die Parameter bereitstellt (keine externen Klassen oder Statiken mehr).
  • Sie können die tatsächlichen Parameterwerte in Ihrer IDE sehen (in JUnits Parametrised sind es nur fortlaufende Anzahlen von Parametern).

1

Wenn TestNG eine Option ist, können Sie Parameter mit DataProvidern verwenden .

Das Ergebnis jeder einzelnen Datei wird im textbasierten Bericht oder in der Benutzeroberfläche des TestNG-Plugins von Eclipse angezeigt. Die Anzahl der insgesamt durchgeführten Tests zählt jede Ihrer Dateien einzeln.

Dieses Verhalten unterscheidet sich von JUnit Theories , bei denen alle Ergebnisse unter einem "Theorie" -Eintrag zusammengefasst sind und nur als 1 Test gelten. Wenn Sie eine separate Ergebnisberichterstattung in JUnit wünschen, können Sie parametrisierte Tests ausprobieren .

Test und Eingaben

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

Beispielausgabe

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

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

Ich weiß nichts über Theorien, aber parametrisierte Tests in JUnit werden separat in Eclipse angezeigt und nicht zusammengefasst.
Hans-Peter Störr

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.