¿Cuándo debo escribir pruebas de integración?

30

De acuerdo con las reglas de TDD, las pruebas unitarias se escriben antes del código de producción, pero ¿qué pasa con las pruebas de integración que ejercitan la interacción entre objetos cableados concretos (no simulados)?

¿Deberían escribirse antes de las pruebas unitarias o después del código de producción solo para probar el "cableado"?

Tenga en cuenta que no estoy hablando de pruebas de aceptación o funcionales, sino de pruebas de integración de nivel inferior.

Chedy2149
fuente

Respuestas:

49

El Libro Rspec , entre otros recursos de BDD, sugiere un ciclo como este:

ingrese la descripción de la imagen aquí

En esencia, el proceso es:

While behaviour required
    Write an integration test for a specific behaviour
    While integration test failing
        Write a unit test to fulfil partial behavior
        While unit test failing
            Write code to make unit test pass
        Commit
        While refactoring can be done
            Refactor
            While unit test failing
                Write code to make unit test pass
            Commit
    Push

Descargo de responsabilidad: No tengo dudas de que esto lleva al mejor código y producto, pero puede llevar mucho tiempo. Hay todo tipo de dificultades en torno a los datos y el determinismo, cuando se trata de decir que las pruebas de integración siempre deben pasar. No es apropiado en todas las circunstancias; a veces solo tienes que sacar cosas de la puerta.

Dicho esto, tener un proceso ideal en mente es genial. Le da un punto desde el cual comprometerse.

pdr
fuente
2
Gracias @pdr pero especifiqué que no estaba hablando de las pruebas de aceptación que se escribieron antes / al comienzo de una iteración, estoy interesado en las pruebas de integración de nivel inferior.
Chedy2149
@ chedy2149: Akkh. Perdí ese comentario. Antes de eliminar mi respuesta, creo que debería ser más específico sobre lo que quiere decir con "nivel inferior" en el contexto de las pruebas de integración.
pdr
Nivel inferior: qué comportamiento no están especificados por los usuarios o clientes y cuáles se utilizan para probar las interacciones de clases / componentes que los desarrolladores esperaban.
Chedy2149
44
En realidad, no creo que haga una diferencia si pones "prueba de aceptación" o "prueba de integración" en esa imagen: es una vista idealizada para cualquier tipo de pruebas en diferentes niveles de abstracción. Pero, en mi humilde opinión, el verdadero problema no es que esto puede llevar "mucho tiempo": el problema real es que escribir pruebas de integración "de antemano" contra una interfaz pública que todavía está diseñada con la ayuda de TDD es como disparar a un "objetivo en movimiento" ".
Doc Brown
@DocBrown, ¿entonces su respuesta es después del código de producción y antes del lanzamiento?
Chedy2149
10

El proyecto real me mostró que no es posible escribir pruebas unitarias y luego la integración e incluso la dirección opuesta es incorrecta :-) Por lo tanto, generalmente escribo pruebas unitarias junto con las de integración.

¿Por qué? Permítanme escribir cómo veo ambos tipos de pruebas:

  1. Pruebas unitarias : además de Wikipedia y toda la información conocida, las pruebas unitarias lo ayudan a reducir su diseño , mejorar su modelo y sus relaciones. El flujo es simple: una vez que comienza a escribir un nuevo proyecto / nuevo componente, la mayoría de las veces está haciendo algún tipo de PoC . Cuando haya terminado, siempre tiene métodos largos, clases largas, métodos y clases no coherentes, etc.

    Las pruebas unitarias lo ayudan a eliminar estos problemas, ya que cuando realiza pruebas unitarias reales utilizando simulaciones (sin dependencia de otro componente), las clases descritas anteriormente no se pueden probar. El signo básico de código no comprobable es una gran parte de burla de las pruebas porque se ve obligado a burlarse de muchas dependencias (o situaciones)

  2. Pruebas de integración: las pruebas correctas y de trabajo le dicen que su nuevo componente (o componentes) funcionan juntos o con otros componentes; esta es la definición habitual. Descubrí que las pruebas de integración le ayudan principalmente a definir el flujo de cómo usar su componente desde el lado del consumidor .

    Esto es realmente importante ya que a veces te dice que tu API no tiene sentido desde el exterior.

Bueno, ¿qué sucede una vez que escribí pruebas unitarias y pruebas de integración más tarde?

Obtuve buenas clases, un diseño claro, un buen constructor, métodos cortos y coherentes, IoC listo, etc. Una vez que doy mi clase / API a algún consumidor, por ejemplo, desarrollador de integración o equipo de GUI, no pudo usar mi API, ya que parece poco lógico. , extraño. Solo estaba confundido. Así que reparé la API de acuerdo con su punto de vista, pero también requería reescribir muchas pruebas porque me presionaron para cambiar los métodos y, a veces, incluso el flujo de cómo usar la API.

Bueno, ¿qué sucede una vez que escribí pruebas de integración y pruebas unitarias más tarde?

Obtuve el flujo exacto, buena usabilidad. Lo que también tengo son clases grandes, código no coherente, sin registro, métodos largos. Código de espagueti

Cual es mi consejo

He aprendido el siguiente flujo:

  1. Desarrolle el esqueleto básico de su código.
  2. Escriba pruebas de integración que indiquen si tiene sentido desde el punto de vista del consumidor. El caso de uso básico es suficiente por ahora. La prueba obviamente no funciona.
  3. Escriba el código junto con las pruebas unitarias para cada clase.
  4. Escriba el resto / falta de pruebas de integración. Sería mejor implementar estas pruebas en el n. ° 3 de cómo está mejorando su código.

Tenga en cuenta que hice una pequeña presentación sobre las pruebas de unidad / integración, vea la diapositiva # 21 donde se describe el esqueleto.

Martin Podval
fuente
5

Las pruebas unitarias se utilizan para probar el bit de software comprobable más pequeño posible en una aplicación y para probar su funcionalidad. Cada unidad se prueba por separado antes de fusionarlas en partes o componentes más grandes de la aplicación.

Ahí es donde entran las pruebas de integración :
prueban estas piezas recién creadas que consisten en las unidades probadas previamente durante el montaje de estas piezas. El mejor caso sería escribir las pruebas en este punto mientras se escribe la aplicación en sí.

Ben McDougall
fuente
¿Entonces su respuesta es después del código de producción?
Chedy2149
Esto no responde la pregunta. Él pregunta si el código de producción se escribe después de las pruebas de integración. Su respuesta se puede tomar de cualquier manera.
Reactgular
1
@MathewFoscarini - respuesta actualizada. Espero que se vuelva más claro ahora.
Ben McDougall
Con respecto a las pruebas unitarias, tendría problemas con el " bit de software más pequeño posible ". Pruebe lo que está en el contrato (por ejemplo, los métodos públicos de un objeto, las funciones exportadas de una biblioteca) porque el contrato define lo que tiene que funcionar. Otras cosas son comprobables, pero hacerlo no solo es una pérdida de tiempo, sino también contraproducente.
itsbruce
3

Tiendo a ver las pruebas de integración como muy similares a las pruebas unitarias. En eso estoy tratando un subconjunto del código como un cuadro negro. Por lo tanto, las pruebas de integración son solo una caja más grande.

Prefiero escribirlos antes del código de producción. Esto tiene la ventaja de ayudarme a recordar qué piezas aún no he conectado o que he cambiado un detalle en la interacción de los objetos ligeramente.

Schleis
fuente
Existen diferentes niveles de prueba: prueba de componente de caja blanca, prueba de componente de integración de caja blanca. Prueba de caja negra de componentes, prueba de caja negra de integración. También hay pruebas de sistema de integración.
Alexander.Iljushkin
2

Además de las pruebas de aceptación, tiendo a escribir solo pruebas de integración en los límites de una aplicación, para verificar que se integra bien con sistemas o componentes de terceros.

La idea es crear objetos adaptadores que se traduzcan de cómo el tercero habla a lo que su aplicación necesita, y pruebe estos traductores contra el sistema externo real. Si haces esa prueba primero o la última prueba, creo que es menos importante que con tus pruebas unitarias regulares porque

  • La información de diseño proporcionada por TDD no importa tanto aquí, ya que el diseño es bastante conocido de antemano y, por lo general, no hay nada terriblemente complejo involucrado, solo se mapean las cosas de un sistema a otro.

  • Dependiendo del módulo / sistema que desee abordar, puede requerir mucha exploración, ajustes de configuración, preparación de datos de muestra, lo que lleva tiempo y no encaja realmente bien en un ciclo de retroalimentación TDD corto.

Sin embargo, si realmente se siente más cómodo construyendo su adaptador de forma incremental en pasos pequeños y seguros, definitivamente recomendaría realizar la prueba primero, no puede doler.

Puede encontrar ejemplos de este enfoque aquí: http://davesquared.net/2011/04/dont-mock-types-you-dont-own.html (sexto párrafo) http://blog.8thlight.com/eric- smith / 2011/10/27 / thats-not-yours.html

guillaume31
fuente
aquí está hablando de pruebas de integración que verifican las interacciones entre "nuestro sistema" y las bibliotecas de terceros, ¿qué hay de probar las interacciones contra una plataforma mientras se desarrolla un complemento, por ejemplo?
Chedy2149
Aunque tengo poca experiencia con el desarrollo de complementos, supongo que pueden ser diferentes ya que, por naturaleza, están estrechamente vinculados con la aplicación host, por lo que es posible que desee adoptar esa integración por completo y decidir que no necesita una capa de adaptador. Sin embargo, en ese caso sería muy cuidadoso con el rendimiento de las pruebas; dependiendo de la aplicación host, llamar a su API directamente en una gran cantidad de sus pruebas puede ser muy lento. Si tiene miedo de eso, siempre puede recurrir al enfoque de "capa adicional de abstracción" y utilizar simulaciones + pruebas de integración en los adaptadores.
guillaume31
1

Entonces iba a aceptar la primera respuesta pero fue eliminada.
Para resumirlo
en una iteración dada:

  1. Prueba de unidad de escritura
  2. Escribir código de producción
  3. Escribir pruebas de integración para probar interacciones

Tenga en cuenta las pruebas de integración mientras 1 y 2 para garantizar la capacidad de prueba a nivel de integración.

Las pruebas de integración no se escriben necesariamente de principio a fin en el paso 3, pueden escribirse parcialmente entre los pasos 1 y 2.

Chedy2149
fuente
3
Este resumen ignora por completo la naturaleza iterativa del proceso. Una vez que tenga la API de su código de producción estable hasta cierto punto, puede comenzar a escribir pruebas de integración. Luego puede trabajar en su código de producción nuevamente, y probablemente cambiar o extender sus pruebas de integración. Por lo tanto, en la mayoría de los casos no "escribe pruebas de integración después del código de producción", generalmente hace ambas cosas en cierto grado en paralelo. Y en realidad, esto también depende en gran medida del tipo de software en el que esté trabajando. El pensamiento "blanco y negro" no te lleva más lejos.
Doc Brown
Buen punto. La respuesta parece ignorar la naturaleza iterativa del diseño a través de la refactorización.
Chedy2149
0

Las pruebas unitarias prueban bloques de código discretos dentro de su proyecto.
Las pruebas de integración prueban cómo su código interactúa con otro código: en otras palabras, prueban la interfaz de su código.

Escriba pruebas unitarias cuando desarrolle código detrás de una interfaz.
Escriba pruebas de integración cuando desarrolle la interfaz o cualquier código que implemente la interfaz.

Esto significa que a veces escribirás pruebas de integración muy tarde en un proyecto, porque la mayoría del trabajo está detrás de la interfaz: por ejemplo, un compilador, un servicio web en particular que implementa varias capas de lógica o ... algo que involucra una gran cantidad de lógica interna

Sin embargo, si está implementando un conjunto de servicios REST o refactorizando el modelo de datos y agregando soporte para transacciones XA, entonces comenzará a desarrollar pruebas de integración casi de inmediato, porque la mayor parte de su trabajo se centra en la interfaz, ya sea la API REST o cómo el programa usa el modelo de datos.

Marco
fuente
¿Aceptaría decir que las pruebas unitarias son pruebas de caja blanca y las pruebas de integración son pruebas de caja negra?
Chedy2149
Lamentablemente, eso depende. Las tecnologías para las pruebas de integración han realizado enormes mejoras en los últimos años (al menos en el mundo de Java) para que pueda probar 1 clase, pero en un servidor de aplicaciones. La pregunta entonces es, ¿dónde está la línea entre las pruebas unitarias y las pruebas de integración? ¿Es una prueba de integración cuando prueba su interfaz de código con otras tecnologías, o es una prueba de integración cuando prueba toda su aplicación, pero no necesariamente en el entorno en el que debe ejecutarse?
Marco
En resumen, en algunos casos, las pruebas de integración segura son pruebas de caja negra, pero no en todos los casos.
Marco
FYI: Wiki define las pruebas de integración como "la fase en las pruebas de software en la que los módulos de software individuales se combinan y se prueban como un grupo"
Marco
Exactamente, Marco. Hay integraciones en cada nivel de componente. Nivel de código, nivel de aplicación, nivel de sistema.
Alexander.Iljushkin