Necesito hacer un poco de defensa de los demonios en esta cuestión porque no puedo defenderla bien por falta de experiencia. Aquí está el trato, obtengo conceptualmente las diferencias entre las pruebas unitarias y las pruebas de integración. Al enfocarse específicamente en los métodos de persistencia y el repositorio, una prueba unitaria usaría un simulacro posiblemente a través de un marco como Moq para afirmar que una orden buscada se devolvió como se esperaba.
Digamos que he construido la siguiente prueba de unidad:
[TestMethod]
public void GetOrderByIDTest()
{
//Uses Moq for dependency for getting order to make sure
//ID I set up in 'Arrange' is same one returned to test in 'Assertion'
}
Entonces, si configuro OrderIdExpected = 5
y mi objeto simulado regresa 5
como ID, mi prueba pasará. Lo entiendo. Me unidad a prueba el código para asegurarse de que lo que mis preformas de código devuelve el objeto esperado y el ID y no otra cosa.
El argumento que obtendré es este:
"¿Por qué no simplemente omitir las pruebas unitarias y hacer pruebas de integración? Es importante probar el procedimiento almacenado de la base de datos y su código juntos. Parece demasiado trabajo adicional tener pruebas unitarias y pruebas de integración cuando finalmente quiero saber si la base de datos llama y el código funciona. Sé que las pruebas llevan más tiempo, pero tienen que ejecutarse y probarse de todos modos, por lo que me parece inútil tener ambas. Simplemente pruebe contra lo que importa ".
Podría defenderlo con una definición de libro de texto como: "Bueno, esa es una prueba de integración y tenemos que probar el código por separado como una prueba unitaria y, yada, yada, yada ..." Este es un caso donde una explicación purista de las prácticas vs. la realidad se está perdiendo. A veces me encuentro con esto y si no puedo defender el razonamiento detrás del código de prueba de la unidad que finalmente depende de dependencias externas, entonces no puedo defenderlo.
Cualquier ayuda sobre esta pregunta es muy apreciada, ¡gracias!
fuente
Respuestas:
Las pruebas unitarias y las pruebas de integración tienen diferentes propósitos.
Las pruebas unitarias verifican la funcionalidad de su código ... que obtiene lo que espera del método cuando lo llama. Las pruebas de integración prueban cómo se comporta el código cuando se combinan juntas como un sistema. No esperaría que las pruebas unitarias evaluaran el comportamiento del sistema, ni esperaría que las pruebas de integración verificaran resultados específicos de un método en particular.
Las pruebas unitarias, cuando se realizan correctamente, son más fáciles de configurar que las pruebas de integración. Si confía únicamente en las pruebas de integración, sus pruebas van a:
En pocas palabras: utilice las pruebas de integración para verificar que las conexiones entre los objetos funcionen correctamente, pero primero apóyese en las pruebas unitarias para verificar los requisitos funcionales.
Dicho todo esto, es posible que no necesite pruebas unitarias para ciertos métodos de repositorio. Las pruebas unitarias no deben hacerse con métodos triviales ; Si todo lo que está haciendo es pasar una solicitud de un objeto al código generado por ORM y devolver un resultado, no necesita realizar una prueba unitaria, en la mayoría de los casos; Una prueba de integración es adecuada.
fuente
Estoy del lado de los pragmáticos. No pruebe su código dos veces.
Solo escribimos pruebas de integración para nuestros repositorios. Estas pruebas solo dependen de una configuración de prueba simple que se ejecuta en una base de datos en memoria. Creo que proporcionan todo lo que hace una prueba unitaria, y más.
fuente
Las pruebas unitarias proporcionan un nivel de modularidad que las pruebas de integración (por diseño) no pueden. Cuando un sistema es reprogramado o recompone, (y esto va a pasar) las pruebas de unidad a menudo pueden ser reutilizados, mientras que las pruebas de integración a menudo deben ser re-escrito. Las pruebas de integración que intentan hacer el trabajo de algo que debería estar en una prueba unitaria a menudo hacen demasiado, lo que las hace difíciles de mantener.
Además, incluir pruebas unitarias tiene los siguientes beneficios:
Es posible dividir su trabajo (y aplicar un enfoque DRY) mientras usa las pruebas de Unidad e Integración. Simplemente confíe en pruebas unitarias para unidades pequeñas de funcionalidad, y no repita ninguna lógica que ya esté en una prueba unitaria en una prueba de integración. Esto a menudo conducirá a menos trabajo (y, por lo tanto, menos reelaboración).
fuente
Las pruebas son útiles cuando se rompen: de forma proactiva o reactiva.
Las pruebas unitarias son proactivas y pueden ser una verificación funcional continua, mientras que las pruebas de integración son reactivas en datos falsos / por etapas.
Si el sistema en consideración es más cercano / dependiente de los datos que de la lógica de cálculo, las pruebas de integración deberían tener más importancia.
Por ejemplo, si estamos construyendo un sistema ETL, las pruebas más relevantes serán en torno a los datos (por etapas, falsificados o en vivo). El mismo sistema tendrá algunas pruebas unitarias, pero solo en torno a la validación, el filtrado, etc.
El patrón de repositorio no debe tener lógica computacional o de negocios. Está muy cerca de la base de datos. Pero el repositorio también está cerca de la lógica de negocios que lo usa. Por lo tanto, se trata de alcanzar un EQUILIBRIO.
Las pruebas unitarias pueden probar CÓMO se comporta el repositorio. Las pruebas de integración pueden probar LO QUE REALMENTE OCURRIÓ cuando se llamó al repositorio.
Ahora, "LO QUE REALMENTE SUCEDIÓ" podría parecer muy tentador. Pero esto podría ser muy costoso para ejecutar de manera consistente y repetida. La definición clásica de pruebas frágiles se aplica aquí.
Entonces, la mayoría de las veces, me parece lo suficientemente bueno como para escribir la prueba de la Unidad en un objeto que usa el repositorio. De esta forma, probamos si se llamó al método de repositorio adecuado y se devuelven los resultados simulados adecuados.
fuente
Hay 3 cosas separadas que necesitan pruebas: el procedimiento almacenado, el código que llama al procedimiento almacenado (es decir, su clase de repositorio) y el consumidor. El trabajo del repositorio es generar una consulta y convertir el conjunto de datos devuelto en un objeto de dominio. Hay suficiente código para admitir pruebas unitarias que se separan de la ejecución real de la consulta y la creación del conjunto de datos.
Entonces (este es un ejemplo muy muy simplificado):
Luego, cuando realice la prueba
OrderRepository
, pase una prueba simuladaISqlExecutor
y verifique que el objeto bajo prueba pasa en el SQL correcto (ese es su trabajo) y devuelve unOrder
objeto apropiado dado algún conjunto de datos de resultados (también burlado). Probablemente, la única forma de probar laSqlExecutor
clase concreta es con pruebas de integración, lo suficientemente justo, pero esa es una clase de envoltura delgada y rara vez cambiará, por lo que es un gran problema.Todavía tiene que probar la unidad de sus procedimientos almacenados también.
fuente
Puedo reducir esto a una línea de pensamiento muy simple: favorece las pruebas unitarias porque ayuda a localizar errores. Y haga esto constantemente porque las inconsistencias causan confusión.
Otras razones se derivan de las mismas reglas que guían el desarrollo de OO, ya que también se aplican a las pruebas. Por ejemplo, el principio de responsabilidad única.
Si algunas pruebas unitarias parecen no valer la pena, entonces tal vez sea una señal de que el tema realmente no vale la pena. O tal vez su funcionalidad es más abstracta que su contraparte, y las pruebas para ello (así como su código) pueden abstraerse a un nivel superior.
Como con cualquier cosa, hay excepciones. Y la programación sigue siendo algo así como una forma de arte, por lo que muchos problemas son lo suficientemente diferentes como para justificar la evaluación de cada uno para el mejor enfoque.
fuente