¿Es una mala práctica imponer una orden de ejecución para las pruebas unitarias?

81

Estoy escribiendo pruebas para un proyecto que consta de varios submódulos. Cada caso de prueba que he escrito se ejecuta de forma independiente y borro todos los datos entre las pruebas.

Aunque las pruebas se ejecutan de forma independiente, estoy considerando hacer cumplir una orden de ejecución, ya que algunos casos requieren más de un submódulo. Por ejemplo, un submódulo está generando datos, y otro está ejecutando consultas en los datos. Si el submódulo que genera los datos contiene un error, la prueba para el submódulo de consulta también fallará, incluso si el submódulo funciona bien.

No puedo trabajar con datos ficticios, ya que la funcionalidad principal que estoy probando es la conexión a un servidor remoto de caja negra, que solo obtiene los datos del primer submódulo.

En este caso, ¿está bien imponer una orden de ejecución para las pruebas o es una mala práctica? Siento que hay un olor en esta configuración, pero no puedo encontrar una mejor manera de evitarlo.

editar: la pregunta es de ¿Cómo estructurar las pruebas donde una prueba es la configuración de otra prueba? como "anterior" test no es una configuración, pero prueba el código que realiza la configuración.

    
pregunta Ali Rasim Kocal 03.04.2018 - 15:02
fuente

6 respuestas

234
  

No puedo trabajar con datos ficticios, ya que la funcionalidad principal que estoy probando es la conexión a un servidor remoto de caja negra, que solo obtiene los datos del primer submódulo.

Esta es la parte clave para mí. Puede hablar sobre "pruebas unitarias" y "ejecutarse de forma independiente", pero todas suenan como que dependen de este servidor remoto y dependen del "primer submódulo". Así que todo suena estrechamente acoplado y dependiente del estado externo. Como tal, de hecho estás escribiendo pruebas de integración. Hacer que esas pruebas se ejecuten en un orden específico es bastante normal, ya que dependen en gran medida de factores externos. Una ejecución de prueba ordenada, con la opción de salir temprano de la ejecución de prueba si las cosas van mal, es perfectamente aceptable para las pruebas de integración.

Pero, también valdría la pena echar un vistazo a la estructura de su aplicación. Ser capaz de burlarse del primer submódulo y del servidor externo potencialmente le permitiría escribir verdaderas pruebas unitarias para todos los demás submódulos.

    
respondido por el David Arno 03.04.2018 - 15:57
fuente
32

Sí, es una mala práctica.

En general, una prueba de unidad pretende probar una sola unidad de código (por ejemplo, una única función basada en un estado conocido).

Cuando desea probar una cadena de eventos que pueden suceder en la naturaleza, desea un estilo de prueba diferente, como una prueba de integración. Esto es aún más cierto si depende de un servicio de terceros.

Para realizar pruebas unitarias de este tipo, necesita encontrar una manera de inyectar los datos ficticios, por ejemplo, implementando una interfaz de servicio de datos que refleje la solicitud web pero devuelva datos conocidos de un archivo de datos ficticios local.

    
respondido por el Paul 03.04.2018 - 15:07
fuente
16

El orden de ejecución forzado que usted propone solo tiene sentido si también cancela la ejecución de prueba después del primer error.

Anular la ejecución de la prueba en el primer fallo significa que cada ejecución de la prueba puede descubrir un solo problema y no puede encontrar nuevos problemas hasta que se hayan solucionado todos los problemas anteriores. Si la primera prueba que se ejecuta encuentra un problema que tarda un mes en solucionarse, durante ese mes no se ejecutarán pruebas.

Si no cancela la ejecución de la prueba en la primera falla, entonces la orden de ejecución forzada no le compra nada porque cada prueba fallida debe investigarse de todos modos. Incluso solo para confirmar que la prueba en el submódulo de consulta está fallando debido a la falla que también se identificó en el submódulo generador de datos.

El mejor consejo que puedo dar es escribir las pruebas de tal manera que sea fácil de identificar cuando una falla en una dependencia está causando que la prueba falle.

    
respondido por el Bart van Ingen Schenau 03.04.2018 - 15:32
fuente
7

El olor al que te refieres es la aplicación de un conjunto incorrecto de restricciones y reglas a tus pruebas.

Las pruebas unitarias a menudo se confunden con "pruebas automatizadas" o "pruebas automatizadas realizadas por un programador".

Las pruebas unitarias deben ser pequeñas, independientes y rápidas.

Algunas personas leen incorrectamente esto como "las pruebas automatizadas escritas por un programador deben ser pequeñas e independientes y rápidas" . Pero simplemente significa que si sus pruebas no son pequeñas, independientes y rápidas, no son Pruebas unitarias y, por lo tanto, algunas de las reglas para Pruebas unitarias no deben, no pueden o no deben aplicarse a sus pruebas . Un ejemplo trivial: debe ejecutar sus Pruebas de unidad después de cada compilación, lo que no debe hacer para las pruebas automatizadas que no son rápidas.

Si bien sus pruebas no son Pruebas Unitarias significa que puede omitir una regla y se le permite tener cierta interdependencia entre las pruebas, también descubrió que hay otras reglas que puede haber omitido y necesitará reintroducir, algo para el alcance de otra pregunta.

    
respondido por el Peter 04.04.2018 - 11:10
fuente
6

Como se señaló anteriormente, lo que está ejecutando parece ser una prueba de integración, sin embargo, declara que:

  

Por ejemplo, un submódulo está generando datos, y otro es   Ejecutando consultas sobre los datos. Si el submódulo genera los datos.   contiene un error, la prueba para el submódulo de consulta también fallará,   incluso si el submódulo en sí funciona bien.

Y este puede ser un buen lugar para comenzar a refactorizar. El módulo que ejecuta consultas sobre los datos no debe depender de una implementación concreta del primer módulo (generación de datos). En su lugar, sería mejor inyectar una interfaz que contenga los métodos para obtener esos datos, y luego se puede simular para probar las consultas.

por ejemplo

Si tienes:

class Queries {

    int GetTheNumber() {
        var dataModule = new Submodule1();
        var data = dataModule.GetData();
        return ... run some query on data
    }
}

Prefiere:

interface DataModule {
    Data GetData();
}


class Queries {

    IDataModule _dataModule;

    ctor(IDataModule dataModule) {
       _dataModule = dataModule;
    }

    int GetTheNumber() {
        var data = _dataModule.GetData();
        return ... run some query on data
    }
}

Esto elimina la dependencia de las consultas en su origen de datos y le permite configurar pruebas de unidad fácilmente repetibles para escenarios particulares.

    
respondido por el Paddy 04.04.2018 - 11:58
fuente
6

Las otras respuestas mencionan que ordenar pruebas es malo (lo que ocurre la mayoría de las veces), pero hay una buena razón para imponer la orden en la ejecución de la prueba: asegurarse de que sus pruebas lentas (es decir, las pruebas de integración) se ejecutan después de su velocidad. Pruebas (pruebas que no dependen de otros recursos externos). Esto garantiza que ejecute más pruebas más rápido, lo que puede acelerar el ciclo de retroalimentación.

    
respondido por el Mike Holler 04.04.2018 - 16:10
fuente

Lea otras preguntas en las etiquetas