Junit: divisione test di integrazione e test unitari


126

Ho ereditato un carico di test Junit, ma questi test (a parte la maggior parte non funzionanti) sono una miscela di test unitari e test di integrazione (che richiedono sistemi esterni, db ecc.).

Quindi sto cercando di pensare a un modo per separarli, in modo da poter eseguire il test unitario in modo rapido e piacevole e i test di integrazione successivi.

Le opzioni sono ...

  1. Dividili in directory separate.

  2. Passa a Junit4 (dalla v3) e annota le classi per separarle.

  3. Utilizzare una convenzione di denominazione dei file per indicare cos'è una classe, ad esempio AdapterATest e AdapterAIntergrationTest.

3 ha il problema che Eclipse ha l'opzione "Esegui tutti i test nel progetto / pacchetto o cartella selezionati". Quindi sarebbe molto difficile eseguire i test di integrazione.

2: corre il rischio che gli sviluppatori possano iniziare a scrivere test di integrazione in classi di unit test e diventa solo disordinato.

1: Sembra la soluzione più pulita, ma il mio istinto dice che ci deve essere una soluzione migliore là fuori.

Quindi questa è la mia domanda: in che modo si separano i test di integrazione e i test unitari adeguati?


Vorrei solo ringraziare tutti voi per il vostro contributo, so che questa è una domanda soggettiva e non ha una risposta corretta. Ma mi hai aiutato a capire che non ci sono altre opzioni rispetto a quelle che ho elencato. Penso che andrò con la struttura di directory per il momento e passerò a JUnit4, anche se non uso ancora le annotazioni per dividerle.
Jeff Porter,

Risposte:


10

Attualmente uso directory separate a causa della politica organizzativa (e dell'eredità di Junit 3) ma sto cercando di passare alle annotazioni io stesso ora sono su Junit 4.

Non sarei eccessivamente preoccupato per gli sviluppatori che mettono test di integrazione nelle classi di test unitari, se necessario aggiungi una regola nei tuoi standard di codifica.

Sono interessato a sapere che tipo di altre soluzioni potrebbero esserci oltre alle annotazioni o alla separazione fisica delle classi.


145

Puoi dividerli molto facilmente usando le categorie JUnit e Maven.

Ciò è mostrato molto, molto brevemente di seguito dalla divisione dell'unità e dai test di integrazione.

Definire un'interfaccia marker

Il primo passo nel raggruppare un test usando le categorie è creare un'interfaccia marker.

Questa interfaccia verrà utilizzata per contrassegnare tutti i test che si desidera eseguire come test di integrazione.

public interface IntegrationTest {}

Segna le tue lezioni di prova

Aggiungi l'annotazione di categoria all'inizio della classe di test. Prende il nome della tua nuova interfaccia.

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

Configurare i test dell'unità Maven

Il bello di questa soluzione è che nulla cambia davvero per il lato unit test delle cose.

Aggiungiamo semplicemente un po 'di configurazione al plugin maven surefire per farlo ignorare qualsiasi test di integrazione.

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

Quando si esegue un test mvn clean, verranno eseguiti solo i test unitari non contrassegnati.

Configurare i test di integrazione Maven

Ancora una volta la configurazione per questo è molto semplice.

Per eseguire solo i test di integrazione, utilizzare questo:

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

Se lo avvolgi in un profilo con ID IT, puoi eseguire solo i test rapidi utilizzando mvn clean install. Per eseguire solo i test di integrazione / lente, utilizzare mvn clean install -P IT.

Ma molto spesso, vorrai eseguire i test veloci per impostazione predefinita e tutti i test con -P IT. In tal caso, devi usare un trucco:

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

Come puoi vedere, escludo i test annotati java.io.Serializable. Ciò è necessario perché il profilo erediterà la configurazione predefinita del plug-in Surefire, quindi anche se dici <excludedGroups/>o <excludedGroups></excludedGroups>, com.test.annotation.type.IntegrationTestverrà utilizzato il valore .

Inoltre non è possibile utilizzare nonepoiché deve essere un'interfaccia sul percorso di classe (Maven verificherà questo).

Appunti:

  • La dipendenza da surefire-junit47è necessaria solo quando Maven non passa automaticamente al corridore JUnit 4. L'uso dell'elemento groupso excludedGroupsdovrebbe attivare l'interruttore. Vedi qui .
  • La maggior parte del codice sopra è stato preso dalla documentazione per il plugin Maven Failsafe. Vedere la sezione "Uso delle categorie JUnit" in questa pagina .
  • Durante i miei test, ho scoperto che funziona anche quando usi le @RunWith()annotazioni per eseguire suite o test basati su Spring.

18
Penso che ci sia un errore nel tuo ultimo frammento pom.xml. hai incollato lo stesso frammento della fase "test". esclude ancora i test di integrazione e inoltre non è vincolato a nessuna fase di preparazione.
Alex,

1
In effetti, l'ultimo frammento di pom è un errore di copia e incolla. Dovrebbe mostrare il plugin maven-fail-safe.
Paulo Merson,

2
Quindi quale dovrebbe essere il secondo XML allora? : O
Liv,

Non devi usare il trucco (ultima magia con Serializable) se usi il profilo Maven predefinito
user831217

Questa dovrebbe davvero essere la risposta accettata perché in realtà è una soluzione alla domanda anziché un dibattito filosofico su dove effettuare prove diverse.
Bwvolleyball

40

Utilizziamo Maven Surefire Plugin per eseguire test unitari e Maven Failsafe Plugin per eseguire test di integrazione. I test unitari seguono le **/Test*.java **/*Test.java **/*TestCase.javaconvenzioni di denominazione, i test di integrazione - **/IT*.java **/*IT.java **/*ITCase.java. Quindi in realtà è la tua opzione numero tre.

In un paio di progetti utilizziamo TestNG e definiamo gruppi di test diversi per test di integrazione / unità, ma questo probabilmente non è adatto a te.


1
+1 per la combinazione maven + surefire + fail-safe + junit. Non mi ero reso conto che fail-safe avrebbe eseguito "IT *" automaticamente. Dolce.
PapaFreud,

13

Vorrei passare a Junit4 solo per averlo :)

È possibile separarli in diverse suite di test. Non so come siano organizzati in Junit3, ma dovrebbe essere facile in Junit4 solo creare suite di test e mettere tutti i test unitari reali in una di esse e quindi utilizzare una seconda suite per i test di integrazione.

Ora definisci una configurazione di esecuzione per entrambe le suite in eclipse e puoi facilmente eseguire una singola suite. Queste suite potrebbero anche essere lanciate da un processo automatizzato che consente di eseguire i test unitari ogni volta che cambia l'origine e forse i test di integrazione (se sono veramente grandi) solo una volta al giorno o una volta all'ora.


9

L'uso dell'annotazione a molla IfProfileValue consente di ottenere questo risultato senza un plug-in maven o una configurazione richiesta.

Annota le classi o i metodi del test di integrazione utilizzando IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

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

Per eseguire solo test unitari:

mvn clean test

Per eseguire utilizzando test di integrazione e test unitari:

mvn clean test -Dtest-groups=integration

Inoltre, "Esegui tutti i test" in un IDE eseguirà solo i test unitari. Aggiungi -Dtest-groups=integrationagli argomenti VM per eseguire sia i test di integrazione che quelli di unità.


Questo approccio è semplice e gradevole, ma il problema che ho riscontrato è che per impostazione predefinita mi piacerebbe eseguire tutti i test (inclusi i test di integrazione). Non è possibile con questo approccio, vero?
csalazar,

6

Non c'è una risposta giusta. Come hai spiegato, ci sono diversi modi per farlo che funzionerà. Ho fatto sia lo schema di denominazione dei file sia la divisione delle cose in diverse directory.

Sembra che suddividere le cose in diverse directory potrebbe funzionare meglio per te, e questo mi sembra un po 'più chiaro, quindi mi spingerei verso quello.

Non credo che proverei le annotazioni perché ciò mi sembra più dettagliato. Vuoi davvero questi due tipi di test mescolati insieme nello stesso file? Non lo farei.

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.