Junit: prueba de integración dividida y pruebas unitarias

126

Heredé una carga de prueba Junit, pero estas pruebas (aparte de la mayoría que no funcionan) son una mezcla de pruebas unitarias reales y pruebas de integración (que requieren sistemas externos, db, etc.).

Así que estoy tratando de pensar en una forma de separarlos, de modo que pueda ejecutar la prueba unitaria de manera agradable y rápida y las pruebas de integración después de eso.

Las opciones son ...

  1. Dividirlos en directorios separados.

  2. Vaya a Junit4 (desde v3) y anote las clases para separarlas.

  3. Use una convención de nomenclatura de archivos para saber qué es una clase, es decir, AdapterATest y AdapterAIntergrationTest.

3 tiene el problema de que Eclipse tiene la opción de "Ejecutar todas las pruebas en el proyecto / paquete o carpeta seleccionado". Por lo tanto, sería muy difícil ejecutar las pruebas de integración.

2: corre el riesgo de que los desarrolladores comiencen a escribir pruebas de integración en clases de prueba unitarias y simplemente se vuelve complicado

1: Parece la mejor solución, pero mi instinto dice que debe haber una mejor solución.

Entonces esa es mi pregunta, ¿cómo separan las pruebas de integración y las pruebas unitarias adecuadas?

Jeff Porter
fuente
Me gustaría agradecerles a todos por su aporte, sé que esta es una pregunta subjetiva y no es una respuesta correcta. Pero me has ayudado a darme cuenta de que no hay otras opciones que las que he enumerado. Creo que voy a ir con la estructura del directorio por el momento y pasar a JUnit4, aunque todavía no usaré anotaciones para dividirlos.
Jeff Porter

Respuestas:

10

Actualmente uso directorios separados debido a la política de la organización (y el legado de Junit 3), pero estoy buscando la transición a las anotaciones ahora que estoy en Junit 4.

No me preocuparía demasiado que los desarrolladores pusieran pruebas de integración en sus clases de prueba unitaria; agregue una regla en sus estándares de codificación si es necesario.

Me interesa saber qué otro tipo de soluciones podría haber aparte de las anotaciones o la separación física de las clases.

Steven Mackenzie
fuente
145

Puede dividirlos muy fácilmente usando las categorías JUnit y Maven.

Esto se muestra muy, muy brevemente a continuación dividiendo la unidad y las pruebas de integración.

Definir una interfaz de marcador

El primer paso para agrupar una prueba usando categorías es crear una interfaz de marcador.

Esta interfaz se utilizará para marcar todas las pruebas que desea ejecutar como pruebas de integración.

public interface IntegrationTest {}

Marque sus clases de prueba

Agregue la anotación de categoría a la parte superior de su clase de prueba. Toma el nombre de su nueva interfaz.

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

Configurar las pruebas de la unidad Maven

La belleza de esta solución es que nada cambia realmente para el lado de las pruebas unitarias.

Simplemente agregamos un poco de configuración al plugin maven surefire para que ignore cualquier prueba de integración.

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

Cuando realice una prueba de limpieza de mvn, solo se ejecutarán las pruebas unitarias sin marcar.

Configurar las pruebas de integración de Maven

Nuevamente, la configuración para esto es muy simple.

Para ejecutar solo las pruebas de integración, use esto:

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

Si envuelve esto en un perfil con id IT, solo puede ejecutar las pruebas rápidas con mvn clean install. Para ejecutar solo las pruebas de integración / lentas, use mvn clean install -P IT.

Pero lo más frecuente es que desee ejecutar las pruebas rápidas de forma predeterminada y todas las pruebas con -P IT. Si ese es el caso, entonces tienes que usar un truco:

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

Como puede ver, estoy excluyendo las pruebas que están anotadas java.io.Serializable. Esto es necesario porque el perfil heredará la configuración predeterminada del complemento Surefire, por lo que incluso si dice <excludedGroups/>o <excludedGroups></excludedGroups>, com.test.annotation.type.IntegrationTestse utilizará el valor .

Tampoco puedes usarlo noneya que tiene que ser una interfaz en el classpath (Maven lo verificará).

Notas:

  • La dependencia a surefire-junit47solo es necesaria cuando Maven no cambia automáticamente al corredor JUnit 4. El uso del elemento groupso excludedGroupsdebería activar el interruptor. Vea aquí .
  • La mayor parte del código anterior se tomó de la documentación del complemento Maven Failsafe. Consulte la sección "Uso de categorías JUnit" en esta página .
  • Durante mis pruebas, descubrí que esto incluso funciona cuando usa @RunWith()anotaciones para ejecutar suites o pruebas basadas en Spring.
John Dobie
fuente
18
Creo que hay un error en su último fragmento pom.xml. pegó el mismo fragmento que en la fase de "prueba". Todavía excluye las pruebas de integración y tampoco está vinculado a ninguna fase de Maven.
Alex
1
De hecho, el último fragmento de pom es un error de copiar y pegar. Debería mostrar el complemento maven-failsafe-plugin.
Paulo Merson
2
Entonces, ¿cuál debería ser el segundo xml? : O
Liv
No tiene que usar el truco (última magia con Serializable) si usa el perfil predeterminado de Maven
user831217
Esta realmente debería ser la respuesta aceptada porque en realidad es una solución a la pregunta en lugar de un debate filosófico sobre dónde colocar diferentes pruebas.
Bwvolleyball
40

Utilizamos Maven Surefire Plugin para ejecutar pruebas unitarias y Maven Failsafe Plugin para ejecutar pruebas de integración. Las pruebas unitarias siguen las **/Test*.java **/*Test.java **/*TestCase.javaconvenciones de nomenclatura, pruebas de integración - **/IT*.java **/*IT.java **/*ITCase.java. Así que en realidad es tu opción número tres.

En un par de proyectos usamos TestNG y definimos diferentes grupos de prueba para la integración / pruebas unitarias, pero esto probablemente no sea adecuado para usted.

lexicore
fuente
1
+1 para el maven + surefire + failsafe + junit combo. No me di cuenta de que failsafe ejecutaría "IT *" automáticamente. Dulce.
PapaFreud
13

Me mudaría a Junit4 solo por tenerlo :)

Puede separarlos en diferentes conjuntos de pruebas. No sé cómo están organizados en Junit3, pero debería ser fácil en Junit4 solo construir conjuntos de pruebas y poner todas las pruebas unitarias reales en una de ellas y luego usar un segundo conjunto para las pruebas de integración.

Ahora defina una configuración de ejecución para ambas suites en eclipse y puede ejecutar fácilmente una sola suite. Estas suites también podrían iniciarse desde un proceso automatizado que le permite ejecutar las pruebas unitarias cada vez que cambie la fuente y tal vez las pruebas de integración (si son realmente grandes) solo una vez al día o una vez por hora.

Janusz
fuente
9

El uso de la anotación de resorte IfProfileValue hace posible lograr esto sin necesidad de un complemento o configuración de Maven.

Anote las clases o métodos de prueba de integración utilizando IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

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

Para ejecutar solo con pruebas unitarias:

mvn clean test

Para ejecutar usando pruebas de integración y pruebas unitarias:

mvn clean test -Dtest-groups=integration

Además, "Ejecutar todas las pruebas" en un IDE solo ejecutaría pruebas unitarias. Agregue -Dtest-groups=integrationa los argumentos de VM para ejecutar tanto la integración como las pruebas unitarias.

Mit Mehta
fuente
Este enfoque es agradable y simple, pero el problema que encuentro es que, por defecto, me gustaría ejecutar todas las pruebas (incluidas las pruebas de integración). Eso no es posible con este enfoque, ¿verdad?
csalazar
6

No hay una respuesta correcta. Como ha explicado, hay varias formas de hacerlo que funcionarán. He hecho tanto el esquema de nombres de archivos como la división de cosas en diferentes directorios.

Parece que dividir las cosas en diferentes directorios podría funcionar mejor para usted, y eso me parece un poco más claro, por lo que me inclinaría hacia eso.

No creo que intente las anotaciones porque eso me parece más detallado. ¿Realmente desea que estos dos tipos de pruebas se mezclen en el mismo archivo? Yo no lo haría

ndp
fuente