Junit: dzielenie testu integracji i testów jednostkowych

126

Odziedziczyłem ładunek testu Junit, ale testy te (poza większością nie działają) są mieszaniną rzeczywistych testów jednostkowych i testów integracyjnych (wymagających systemów zewnętrznych, db itp.).

Próbuję więc wymyślić sposób, aby je oddzielić, tak żebym mógł szybko i przyjemnie przeprowadzić testy jednostkowe, a potem testy integracji.

Dostępne opcje to ...

  1. Podziel je na osobne katalogi.

  2. Przejdź do Junit4 (od v3) i dodaj adnotacje do klas, aby je rozdzielić.

  3. Użyj konwencji nazewnictwa plików, aby określić, czym jest klasa, tj. AdapterATest i AdapterAIntergrationTest.

3 występuje problem polegający na tym, że Eclipse ma opcję „Uruchom wszystkie testy w wybranym projekcie / pakiecie lub folderze”. Dlatego wykonanie testów integracyjnych byłoby bardzo trudne.

2: stwarza ryzyko, że programiści mogą zacząć pisać testy integracyjne w klasach testów jednostkowych i po prostu robi się bałagan.

1: Wydaje się, że jest to najlepsze rozwiązanie, ale moje przeczucia mówią, że musi być lepsze rozwiązanie.

To jest moje pytanie, w jaki sposób rozdzielić testy integracyjne i właściwe testy jednostkowe?

jeff porter
źródło
Chciałbym tylko podziękować wszystkim za wkład, wiem, że jest to pytanie subiektywne i nie ma jednej poprawnej odpowiedzi. Ale pomogłeś mi zrozumieć, że nie ma innych opcji niż te, które wymieniłem. Myślę, że zamierzam na razie przejść do struktury katalogów i przejść do JUnit4, chociaż nie używam jeszcze adnotacji do ich dzielenia.
jeff porter,

Odpowiedzi:

10

Obecnie używam oddzielnych katalogów ze względu na politykę organizacyjną (i starszą wersję Junit 3), ale chcę samodzielnie przejść do adnotacji, teraz jestem w Junit 4.

Nie przejmowałbym się zbytnio, gdyby programiści umieszczali testy integracji w klasach testów jednostkowych - w razie potrzeby dodaj regułę do standardów kodowania.

Interesuje mnie, jakie inne rozwiązania mogą istnieć poza adnotacjami lub fizycznym oddzieleniem klas.

Steven Mackenzie
źródło
145

Możesz je bardzo łatwo podzielić za pomocą kategorii JUnit i Maven.

Pokazano to bardzo, bardzo krótko poniżej, dzieląc testy jednostkowe i integracyjne.

Zdefiniuj interfejs znacznika

Pierwszym krokiem w grupowaniu testu za pomocą kategorii jest utworzenie interfejsu znaczników.

Ten interfejs będzie używany do oznaczania wszystkich testów, które chcesz uruchomić, jako testy integracji.

public interface IntegrationTest {}

Zaznacz swoje klasy testowe

Dodaj adnotację kategorii na początku klasy testowej. Przyjmuje nazwę nowego interfejsu.

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

Skonfiguruj testy jednostkowe Maven

Piękno tego rozwiązania polega na tym, że nic tak naprawdę nie zmienia się po stronie testów jednostkowych.

Po prostu dodajemy konfigurację do wtyczki maven surefire, aby ignorowała wszelkie testy integracji.

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

Kiedy wykonujesz czysty test mvn, zostaną uruchomione tylko nieoznakowane testy jednostkowe.

Skonfiguruj testy integracji Maven

Ponownie konfiguracja tego jest bardzo prosta.

Aby uruchomić tylko testy integracji, użyj tego:

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

Jeśli umieścisz to w profilu o identyfikatorze IT, możesz uruchomić tylko szybkie testy przy użyciu mvn clean install. Aby uruchomić tylko integrację / wolne testy, użyj mvn clean install -P IT.

Ale najczęściej będziesz chciał domyślnie uruchamiać szybkie testy, a wszystkie testy z -P IT. W takim przypadku musisz użyć sztuczki:

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

Jak widać, wykluczam testy z adnotacją java.io.Serializable. Jest to konieczne, ponieważ profil odziedziczy domyślną konfigurację wtyczki Surefire, więc nawet jeśli powiesz <excludedGroups/>lub <excludedGroups></excludedGroups>, wartość com.test.annotation.type.IntegrationTestzostanie użyta.

Nie możesz również użyć, noneponieważ musi to być interfejs na ścieżce klas (Maven to sprawdzi).

Uwagi:

  • Zależność od surefire-junit47jest konieczna tylko wtedy, gdy Maven nie przełącza się automatycznie na biegacz JUnit 4. Użycie elementu groupslub excludedGroupspowinno wywołać przełącznik. Zobacz tutaj .
  • Większość powyższego kodu pochodzi z dokumentacji wtyczki Maven Failsafe. Zobacz sekcję „Korzystanie z kategorii JUnit” na tej stronie .
  • Podczas moich testów odkryłem, że działa to nawet, gdy używasz @RunWith()adnotacji do uruchamiania pakietów lub testów opartych na Spring.
John Dobie
źródło
18
Myślę, że w ostatnim fragmencie pom.xml jest błąd. wkleiłeś ten sam fragment, co w przypadku fazy „testowej”. nadal wyklucza testy integracji, a także nie jest związany z żadną fazą twórczą.
Alex
1
Rzeczywiście, ostatni fragment pom to błąd kopiowania i wklejania. Powinien pokazać wtyczkę maven-failafe-plugin.
Paulo Merson
2
Więc jaki powinien być drugi plik XML? : O
Liv
Nie musisz używać tej sztuczki (ostatnia magia z Serializable), jeśli używasz domyślnego profilu Maven
user831217
To naprawdę powinna być akceptowana odpowiedź, ponieważ w rzeczywistości jest to rozwiązanie pytania, a nie filozoficzna debata o tym, gdzie umieścić różne testy.
Bwvolleyball
40

Używamy wtyczki Maven Surefire do uruchamiania testów jednostkowych i wtyczki Maven Failsafe do uruchamiania testów integracyjnych. Testy jednostkowe są zgodne z **/Test*.java **/*Test.java **/*TestCase.javakonwencjami nazewnictwa, testy integracji - **/IT*.java **/*IT.java **/*ITCase.java. Więc to właściwie twoja opcja numer trzy.

W kilku projektach używamy TestNG i definiujemy różne grupy testowe do testów integracyjnych / jednostkowych, ale to prawdopodobnie nie jest dla Ciebie odpowiednie.

leksykor
źródło
1
+1 dla kombinacji Maven + surefire + failafe + junit. Nie zdawałem sobie sprawy, że w przypadku awarii można uruchomić „IT *” w sposób automagiczny. Słodkie.
PapaFreud
13

Przeniósłbym się do Junit4 tylko po to, żeby go mieć :)

Możesz podzielić je na różne zestawy testów. Nie wiem, jak są zorganizowane w Junit3, ale w Junit4 powinno być łatwo po prostu zbudować zestawy testów i umieścić wszystkie prawdziwe testy jednostkowe w jednym z nich, a następnie użyć drugiego zestawu do testów integracyjnych.

Teraz zdefiniuj konfigurację uruchamiania dla obu pakietów w eclipse i możesz łatwo uruchomić pojedynczy pakiet. Pakiety te można również uruchamiać z zautomatyzowanego procesu, umożliwiającego uruchamianie testów jednostkowych za każdym razem, gdy zmienia się źródło, a być może testy integracyjne (jeśli są naprawdę duże) tylko raz dziennie lub raz na godzinę.

Janusz
źródło
9

Korzystanie z adnotacji sprężynowej IfProfileValue umożliwia osiągnięcie tego bez wtyczki maven lub wymaganej konfiguracji.

Adnotuj klasy lub metody testu integracji przy użyciu właściwości IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

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

Aby uruchomić tylko przy użyciu testów jednostkowych:

mvn clean test

Aby uruchomić przy użyciu testu integracji i testów jednostkowych:

mvn clean test -Dtest-groups=integration

Ponadto „Uruchom wszystkie testy” w środowisku IDE spowoduje uruchomienie tylko testu jednostkowego. Dodaj -Dtest-groups=integrationdo argumentów maszyny wirtualnej, aby uruchomić zarówno testy integracji, jak i testy jednostkowe.

Mit Mehta
źródło
Takie podejście jest przyjemne i proste, ale moim problemem jest to, że domyślnie chciałbym uruchomić wszystkie testy (w tym testy integracyjne). To niemożliwe przy takim podejściu, prawda?
csalazar
6

Nie ma jednej dobrej odpowiedzi. Jak już wyjaśniłeś, jest na to kilka sposobów, które będą działać. Zrobiłem zarówno schemat nazewnictwa plików, jak i podzieliłem rzeczy na różne katalogi.

Wygląda na to, że podzielenie rzeczy na różne katalogi może działać lepiej dla ciebie, a to wydaje mi się trochę jaśniejsze, więc skłaniam się ku temu.

Nie sądzę, żebym próbował adnotacji, ponieważ wydaje mi się to bardziej szczegółowe. Czy naprawdę chcesz, aby te dwa typy testów były zmieszane razem w tym samym pliku? Nie chciałbym.

ndp
źródło