it-swarm-eu.dev

Haken vor und nach der Ausführung der Suite in jUnit 4.x

Ich versuche, Setup und Teardown für eine Reihe von Integrationstests durchzuführen, indem ich jUnit 4.4 verwende, um die Tests auszuführen. Der Abbau muss zuverlässig verlaufen. Ich habe andere Probleme mit TestNG, daher möchte ich wieder auf jUnit portieren. Welche Hooks stehen zur Ausführung zur Verfügung, bevor Tests ausgeführt werden und nachdem alle Tests abgeschlossen wurden?

Hinweis: Wir verwenden Maven 2 für unseren Build. Ich habe versucht, die Phasen pre- Und post-integration-test Von Maven zu verwenden, aber wenn ein Test fehlschlägt, stoppt Maven und führt post-integration-test Nicht aus, was keine Hilfe ist.

81
sblundy

Ja, es ist möglich, vor und nach jedem Test in einer Testsuite Rüst- und Abbruchmethoden zuverlässig auszuführen. Lassen Sie mich im Code demonstrieren:

package com.test;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class TestSuite {

    @BeforeClass
    public static void setUp() {
        System.out.println("setting up");
    }

    @AfterClass
    public static void tearDown() {
        System.out.println("tearing down");
    }

}

Ihre Test1-Klasse würde also ungefähr so ​​aussehen:

package com.test;

import org.junit.Test;


public class Test1 {
    @Test
    public void test1() {
        System.out.println("test1");
    }

}

... und Sie können sich vorstellen, dass Test2 ähnlich aussieht. Wenn Sie TestSuite ausführen, erhalten Sie:

setting up
test1
test2
tearing down

Sie können also sehen, dass das Auf- und Abbauen nur vor bzw. nach allen Tests ausgeführt wird.

Der Haken: Dies funktioniert nur, wenn Sie die Testsuite ausführen und nicht Test1 und Test2 als einzelne JUnit-Tests. Sie haben erwähnt, dass Sie Maven verwenden, und das Maven-todsichere Plug-in führt Tests gerne einzeln aus und ist nicht Teil einer Suite. In diesem Fall würde ich empfehlen, eine Superklasse zu erstellen, die von jeder Testklasse erweitert wird. Die Superklasse enthält dann die mit Annotationen versehenen Methoden @BeforeClass und @AfterClass. Obwohl nicht ganz so sauber wie die obige Methode, denke ich, dass es für Sie funktionieren wird.

Was das Problem mit fehlgeschlagenen Tests betrifft, können Sie maven.test.error.ignore so einstellen, dass der Build bei fehlgeschlagenen Tests fortgesetzt wird. Dies wird nicht als fortlaufende Übung empfohlen, sollte Sie jedoch zum Funktionieren bringen, bis alle Ihre Tests bestanden sind. Weitere Einzelheiten finden Sie in der maven todsichere Dokumentation .

111
Julie

Ein Kollege von mir schlug Folgendes vor: Sie können einen benutzerdefinierten RunListener verwenden und die testRunFinished () -Methode implementieren: http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html# testRunFinished (org.junit.runner.Result)

Um den RunListener zu registrieren, konfigurieren Sie das todsichere Plugin wie folgt: http://maven.Apache.org/surefire/maven-surefire-plugin/examples/junit.html Abschnitt "Benutzerdefinierte Listener und Reporter verwenden"

Diese Konfiguration sollte auch vom ausfallsicheren Plugin ausgewählt werden. Diese Lösung ist großartig, da Sie keine Suites, Lookup-Testklassen oder ähnliches angeben müssen. Sie ermöglicht Maven, seine Magie zu entfalten und darauf zu warten, dass alle Tests abgeschlossen sind.

32
Martin Vysny
11
Tobogganski

Mit Anmerkungen können Sie Folgendes tun:

import org.junit.*;
import static org.junit.Assert.*;
import Java.util.*;

class SomethingUnitTest {
    @BeforeClass
    public static void runBeforeClass()
    {

    }

    @AfterClass
    public static void runAfterClass()
    {  

    }

    @Before  
    public void setUp()
    {

    }

    @After
    public void tearDown()
    {

    }

    @Test
    public void testSomethingOrOther()
    {

    }

}
7
Jroc

Hier, wir

  • upgrade auf JUnit 4.5,
  • anmerkungen geschrieben, um jede Testklasse oder Methode zu kennzeichnen, die einen funktionierenden Dienst benötigt,
  • handler für jede Annotation geschrieben, die statische Methoden enthielten, um das Einrichten und Herunterfahren des Dienstes zu implementieren,
  • der übliche Runner wurde erweitert, um die Anmerkungen zu Tests zu lokalisieren, und die statischen Handlermethoden wurden an den entsprechenden Stellen in die Testausführungskette eingefügt.
3
carym

Vorausgesetzt, dass alle Ihre Tests eine "technische" Klasse erweitern und sich im selben Paket befinden, können Sie einen kleinen Trick machen:

public class AbstractTest {
  private static int nbTests = listClassesIn(<package>).size();
  private static int curTest = 0;

  @BeforeClass
  public static void incCurTest() { curTest++; }

  @AfterClass
  public static void closeTestSuite() {
      if (curTest == nbTests) { /*cleaning*/ }             
  }
}

public class Test1 extends AbstractTest {
   @Test
   public void check() {}
}
public class Test2 extends AbstractTest {
   @Test
   public void check() {}
}

Beachten Sie, dass diese Lösung viele Nachteile hat:

  • muss alle Tests des Pakets ausführen
  • muss eine "techincal" -Klasse unterordnen
  • sie können @BeforeClass und @AfterClass nicht in Unterklassen verwenden
  • wenn Sie nur einen Test im Paket ausführen, wird die Reinigung nicht durchgeführt
  • ...

Zur Information: listClassesIn () => Wie finden Sie alle Unterklassen einer bestimmten Klasse in Java?

2
christophe blin

Was "Hinweis: Wir verwenden Maven 2 für unseren Build. Ich habe versucht, die Testphasen vor und nach der Integration von Maven zu verwenden, aber wenn ein Test fehlschlägt, stoppt Maven und führt den Test nach der Integration nicht aus , das ist keine Hilfe. "

sie können stattdessen das Failsafe-Plugin ausprobieren. Ich denke, es verfügt über die Möglichkeit, sicherzustellen, dass die Bereinigung unabhängig von Setup- oder Zwischenstufenstatus erfolgt

2
Binod Pant

Wenn Sie keine Suite erstellen möchten und alle Testklassen auflisten müssen, können Sie Reflection verwenden, um die Anzahl der Testklassen dynamisch zu ermitteln und in einer Basisklasse @AfterClass herunterzuzählen, um den Abreißvorgang nur einmal auszuführen:

public class BaseTestClass
{
    private static int testClassToRun = 0;

    // Counting the classes to run so that we can do the tear down only once
    static {
        try {
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);

            @SuppressWarnings({ "unchecked", "rawtypes" })
            Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
            for (Class<?> clazz : classes) {
                if (clazz.getName().endsWith("Test")) {
                    testClassToRun++;
                }
            }
        } catch (Exception ignore) {
        }
    }

    // Setup that needs to be done only once
    static {
        // one time set up
    }

    @AfterClass
    public static void baseTearDown() throws Exception
    {
        if (--testClassToRun == 0) {
            // one time clean up
        }
    }
}

Wenn Sie @BeforeClass anstelle der statischen Blöcke verwenden möchten, können Sie auch ein Boolesches Flag verwenden, um die Reflexionszählung und die Testeinrichtung nur einmal beim ersten Aufruf durchzuführen. Ich hoffe, das hilft jemandem. Ich habe einen Nachmittag gebraucht, um einen besseren Weg zu finden, als alle Klassen in einer Suite aufzuzählen.

Jetzt müssen Sie diese Klasse nur noch für alle Ihre Testklassen erweitern. Wir hatten bereits eine Basisklasse, die einige allgemeine Informationen für alle unsere Tests bereitstellte, daher war dies die beste Lösung für uns.

Inspiration kommt von dieser SO Antwort https://stackoverflow.com/a/37488620/5930242

Wenn Sie diese Klasse nicht überall erweitern möchten, kann diese SO Antwort tun, was Sie wollen.

0
FredBoutin

Da das maven-surefire-plugin Suite class nicht zuerst ausführt, sondern Suite- und Testklassen gleich behandelt, können wir das Plugin wie folgt konfigurieren, um nur Suite-Klassen zu aktivieren und alle Tests zu deaktivieren. Die Suite führt alle Tests durch.

        <plugin>
            <groupId>org.Apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.5</version>
            <configuration>
                <includes>
                    <include>**/*Suite.Java</include>
                </includes>
                <excludes>
                    <exclude>**/*Test.Java</exclude>
                    <exclude>**/*Tests.Java</exclude>
                </excludes>
            </configuration>
        </plugin>
0
Anurag Sharma

Ich denke, die einzige Möglichkeit, um die gewünschte Funktionalität zu erhalten, besteht darin, so etwas zu tun

import junit.framework.Test;  
import junit.framework.TestResult;  
import junit.framework.TestSuite;  

public class AllTests {  
    public static Test suite() {  
        TestSuite suite = new TestSuite("TestEverything");  
        //$JUnit-BEGIN$  
        suite.addTestSuite(TestOne.class);  
        suite.addTestSuite(TestTwo.class);  
        suite.addTestSuite(TestThree.class);  
        //$JUnit-END$  
     }  

     public static void main(String[] args)  
     {  
        AllTests test = new AllTests();  
        Test testCase = test.suite();  
        TestResult result = new TestResult();  
        setUp();  
        testCase.run(result);  
        tearDown();  
     }  
     public void setUp() {}  
     public void tearDown() {}  
} 

Ich verwende so etwas in Eclipse, daher bin ich mir nicht sicher, wie portabel es außerhalb dieser Umgebung ist

0
Jroc

Soweit ich weiß, gibt es in JUnit keinen Mechanismus, um dies zu tun. Sie könnten jedoch versuchen, Suite zu unterklassifizieren und die run () -Methode mit einer Version zu überschreiben, die Hooks bereitstellt.

0
user15299