Junit: Aufteilung des Integrationstests und Unit-Tests


126

Ich habe eine Menge Junit-Tests geerbt, aber diese Tests (abgesehen von den meisten, die nicht funktionieren) sind eine Mischung aus tatsächlichen Unit-Tests und Integrationstests (für die externe Systeme, Datenbank usw. erforderlich sind).

Also versuche ich mir eine Möglichkeit zu überlegen, sie tatsächlich zu trennen, damit ich den Komponententest schön und schnell und die Integrationstests danach ausführen kann.

Die Optionen sind ..

  1. Teilen Sie sie in separate Verzeichnisse auf.

  2. Wechseln Sie zu Junit4 (von Version 3) und kommentieren Sie die Klassen, um sie zu trennen.

  3. Verwenden Sie eine Dateinamenskonvention, um festzustellen, was eine Klasse ist, z. B. AdapterATest und AdapterAIntergrationTest.

3 hat das Problem, dass Eclipse die Option "Alle Tests im ausgewählten Projekt / Paket oder Ordner ausführen" hat. Daher wäre es sehr schwierig, nur die Integrationstests auszuführen.

2: läuft Gefahr, dass Entwickler anfangen, Integrationstests in Unit-Test-Klassen zu schreiben, und es wird nur chaotisch.

1: Scheint die sauberste Lösung zu sein, aber mein Bauch sagt, dass es da draußen eine bessere Lösung geben muss.

Das ist also meine Frage, wie zerlegt man Integrationstests und richtige Unit-Tests?


Ich möchte mich nur bei Ihnen allen für Ihre Beiträge bedanken. Ich weiß, dass dies eine subjektive Frage ist und keine richtige Antwort. Aber Sie haben mir dabei geholfen zu erkennen, dass es keine anderen Optionen gibt als die, die ich aufgelistet habe. Ich denke, ich werde im Moment mit der Verzeichnisstruktur arbeiten und zu JUnit4 wechseln, obwohl ich noch keine Anmerkungen zum Aufteilen verwende.
Jeff Porter

Antworten:


10

Ich verwende derzeit aufgrund der Organisationsrichtlinien (und des Junit 3-Erbes) separate Verzeichnisse, möchte aber jetzt selbst zu Anmerkungen übergehen, da ich auf Junit 4 bin.

Ich wäre nicht übermäßig besorgt darüber, dass Entwickler Integrationstests in Ihre Unit-Test-Klassen aufnehmen - fügen Sie bei Bedarf eine Regel in Ihre Codierungsstandards ein.

Ich bin interessiert zu wissen, welche anderen Lösungen es neben Anmerkungen oder der physischen Trennung der Klassen geben könnte.


145

Sie können sie sehr einfach mit JUnit-Kategorien und Maven aufteilen.

Dies wird im Folgenden sehr, sehr kurz durch Aufteilen von Einheiten- und Integrationstests gezeigt.

Definieren Sie eine Marker-Schnittstelle

Der erste Schritt beim Gruppieren eines Tests anhand von Kategorien besteht darin, eine Markierungsschnittstelle zu erstellen.

Diese Schnittstelle wird verwendet, um alle Tests, die Sie ausführen möchten, als Integrationstests zu markieren.

public interface IntegrationTest {}

Markieren Sie Ihre Testklassen

Fügen Sie die Kategorieanmerkung oben in Ihrer Testklasse hinzu. Es nimmt den Namen Ihrer neuen Schnittstelle an.

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest{
  @Test
  public void longRunningServiceTest() throws Exception {
  }
}

Konfigurieren Sie Maven Unit Tests

Das Schöne an dieser Lösung ist, dass sich für den Unit-Test nichts wirklich ändert.

Wir fügen dem Maven Surefire-Plugin einfach eine Konfiguration hinzu, damit Integrationstests ignoriert werden.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

Wenn Sie einen MVN-Bereinigungstest durchführen, werden nur Ihre nicht markierten Komponententests ausgeführt.

Konfigurieren Sie Maven-Integrationstests

Auch hier ist die Konfiguration sehr einfach.

Verwenden Sie Folgendes, um nur die Integrationstests auszuführen:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

Wenn Sie dies in ein Profil mit der ID einbinden IT, können Sie nur die Schnelltests mit ausführen mvn clean install. Verwenden Sie, um nur die Integrations- / langsamen Tests auszuführen mvn clean install -P IT.

In den meisten Fällen möchten Sie jedoch standardmäßig die schnellen Tests und alle Tests mit ausführen -P IT. Wenn das der Fall ist, müssen Sie einen Trick anwenden:

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Wie Sie sehen können, schließe ich Tests aus, die mit Anmerkungen versehen sind java.io.Serializable. Dies ist erforderlich, da das Profil die Standardkonfiguration des Surefire-Plugins erbt. Selbst wenn Sie <excludedGroups/>oder sagen <excludedGroups></excludedGroups>, wird der Wert com.test.annotation.type.IntegrationTestverwendet.

Sie können es auch nicht verwenden, noneda es sich um eine Schnittstelle im Klassenpfad handeln muss (Maven überprüft dies).

Anmerkungen:

  • Die Abhängigkeit von surefire-junit47ist nur erforderlich, wenn Maven nicht automatisch zum JUnit 4-Runner wechselt. Die Verwendung des Elements groupsoder excludedGroupssollte den Schalter auslösen. Siehe hier .
  • Der größte Teil des obigen Codes stammt aus der Dokumentation für das Maven Failsafe-Plugin. Siehe den Abschnitt "Verwenden von JUnit-Kategorien" auf dieser Seite .
  • Während meiner Tests stellte ich fest, dass dies sogar funktioniert, wenn Sie @RunWith()Anmerkungen zum Ausführen von Suites oder Spring-basierten Tests verwenden.

18
Ich denke, es gibt einen Fehler in Ihrem letzten pom.xml-Fragment. Sie haben das gleiche Snippet wie für die "Test" -Phase eingefügt. Es schließt die Integrationstests weiterhin aus und ist auch nicht an eine Maven-Phase gebunden.
Alex

1
In der Tat ist das letzte Pom-Fragment ein Fehler beim Kopieren und Einfügen. Es sollte das Maven-Failsafe-Plugin anzeigen.
Paulo Merson

2
Was sollte dann die zweite XML sein? : O
Liv

Sie müssen den Trick nicht
anwenden

Dies sollte wirklich die akzeptierte Antwort sein, da dies tatsächlich eine Lösung für die Frage ist, anstatt eine philosophische Debatte darüber, wo verschiedene Tests platziert werden sollen.
Bwvolleyball

40

Wir verwenden das Maven Surefire Plugin, um Unit-Tests durchzuführen, und das Maven Failsafe Plugin, um Integrationstests durchzuführen. Unit-Tests folgen den **/Test*.java **/*Test.java **/*TestCase.javaNamenskonventionen, Integrationstests - **/IT*.java **/*IT.java **/*ITCase.java. Es ist also tatsächlich Ihre Option Nummer drei.

In einigen Projekten verwenden wir TestNG und definieren verschiedene Testgruppen für Integrations- / Komponententests, aber dies ist wahrscheinlich nicht für Sie geeignet.


1
+1 für den Maven + todsichere + ausfallsichere + Junit-Combo. Ich wusste nicht, dass ausfallsicher "IT *" automatisch ausgeführt werden würde. Süss.
PapaFreud

13

Ich würde auf Junit4 umsteigen, nur weil ich es habe :)

Sie können sie in verschiedene Testsuiten unterteilen. Ich weiß nicht, wie sie in Junit3 organisiert sind, aber es sollte in Junit4 einfach sein, Testsuiten aufzubauen und alle realen Komponententests in einer von ihnen zu platzieren und dann eine zweite Suite für die Integrationstests zu verwenden.

Definieren Sie jetzt eine Ausführungskonfiguration für beide Suites in Eclipse, und Sie können problemlos eine einzelne Suite ausführen. Diese Suiten können auch über einen automatisierten Prozess gestartet werden, sodass Sie die Komponententests jedes Mal ausführen können, wenn sich die Quelle ändert, und möglicherweise die Integrationstests (wenn sie wirklich groß sind) nur einmal am Tag oder einmal pro Stunde.


9

Die Verwendung der IfProfileValue-Federanmerkung ermöglicht dies, ohne dass ein Maven-Plugin oder eine Konfiguration erforderlich ist.

Kommentieren Sie die Integrationstestklassen oder -methoden mit IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest{
    @Test
    public void longRunningServiceTest() throws Exception {
    }
} 

Nur mit Komponententests ausführen:

mvn clean test

So führen Sie den Integrationstest und Unit-Tests aus:

mvn clean test -Dtest-groups=integration

Außerdem würde "Alle Tests ausführen" in einer IDE nur den Komponententest ausführen. Fügen Sie -Dtest-groups=integrationVM-Argumente hinzu, um sowohl Integrations- als auch Komponententests auszuführen.


Dieser Ansatz ist nett und einfach, aber das Problem, das ich finde, ist, dass ich standardmäßig alle Tests (einschließlich Integrationstests) ausführen möchte. Das ist mit diesem Ansatz nicht möglich, oder?
Csalazar

6

Es gibt keine richtige Antwort. Wie Sie erklärt haben, gibt es verschiedene Möglichkeiten, die funktionieren. Ich habe sowohl das Dateinamenschema als auch die Aufteilung in verschiedene Verzeichnisse durchgeführt.

Es hört sich so an, als würde die Aufteilung in verschiedene Verzeichnisse für Sie besser funktionieren, und das scheint mir etwas klarer zu sein, also würde ich mich dazu neigen.

Ich glaube nicht, dass ich Anmerkungen versuchen würde, weil mir das feinkörniger erscheint. Möchten Sie wirklich, dass diese beiden Arten von Tests in derselben Datei gemischt werden? Ich würde nicht.

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.