Por lo tanto, estoy tratando de hacer que mis Pruebas de Unidad sean lo más exacta posible, pero se vuelve problemático cuando estoy probando algunos métodos simples de Agregar / Eliminar.
Para el método de agregar, básicamente tengo que crear un objeto ficticio y agregarlo, luego, después de que la prueba sea exitosa, tengo que eliminar el objeto ficticio.
Y para la prueba de eliminación, obviamente tengo que crear un objeto ficticio para poder eliminarlo.
Como puede ver si una prueba falla, la otra también fallará, ya que ambas son un poco necesarias.
Lo mismo con un sistema en el que necesitaría escribir una prueba que "cancela una orden" ... bueno, se necesitaría una orden ficticia para cancelar primero, ¿no va esto en contra de las pautas de las pruebas unitarias?
¿Cómo se manejan casos como este?
fuente
Respuestas:
Bueno, no hay nada malo con lo que estás haciendo. Múltiples pruebas pueden cubrir el mismo código; solo significa que un problema hará que varias pruebas fallen. Lo que desea evitar son las pruebas que dependen de los resultados de otras pruebas. Es decir, su prueba de eliminación depende de que se haya ejecutado la prueba de adición y, por lo tanto, si ejecuta su prueba de eliminación ANTES de su prueba de adición, fallará. Para evitar ese problema, asegúrese de tener una "pizarra en blanco" al comienzo de cada prueba, de modo que lo que sucede en una prueba dada no pueda afectar las pruebas posteriores.
Una excelente manera de hacerlo es ejecutar las pruebas en una base de datos en memoria.
En su prueba de agregar, cree una base de datos vacía, agregue el objeto y afirme que efectivamente se ha agregado.
En su prueba de eliminación, cree la base de datos con el objeto que eliminará ya en ella. Elimine el objeto y afirme que se ha eliminado.
Elimine la base de datos en su código desmontable.
fuente
Usar transacciones.
Si está utilizando una base de datos que admite transacciones, ejecute cada prueba en una transacción. Revierta la transacción al final de la prueba. Luego, cada prueba dejará la base de datos sin cambios.
Sí, para cancelar un pedido, primero tendrá que crear uno. Esta bien. La prueba creará primero un pedido, luego lo cancelará, luego verificará que el pedido se cancele.
fuente
Lo estás haciendo bien El único principio fundamental de las pruebas unitarias es cubrir cada ruta de código que tenga, de modo que pueda estar seguro de que su código está haciendo lo que se supone que debe hacer, y lo sigue haciendo después de los cambios y refactorizaciones. Mantener pruebas unitarias pequeñas, simples y de un solo propósito es un objetivo que vale la pena, pero no es fundamental. Tener una prueba que llame a dos métodos relacionados de su API no es en sí mismo cuestionable, de hecho, como usted señala, a menudo es necesario. El inconveniente de tener pruebas redundantes es que tardan más en escribir, pero como casi todo en desarrollo, esta es una compensación que debes hacer todo el tiempo, y la mejor solución casi nunca es uno de los puntos extremos.
fuente
Las técnicas de prueba de software son extremadamente variadas, y cuanto más se eduque acerca de ellas, comenzará a ver mucha orientación diferente (y a veces conflictiva). No hay un solo 'libro' para seguir.
Creo que estás en una situación en la que has visto alguna guía para las pruebas unitarias que dicen cosas como
y así. Y todo eso es correcto, dependiendo de cómo defina 'prueba unitaria' .
Definiría una 'prueba de unidad' como algo así como: "una prueba que ejercita una pieza de funcionalidad para una unidad de código, aislada de otros componentes dependientes".
Según esa definición, lo que está haciendo (si requiere agregar un registro a una base de datos antes de poder ejecutar la prueba) no es una 'prueba unitaria' en absoluto, sino más de lo que comúnmente se llama una 'prueba de integración'. (Una verdadera prueba unitaria, según mi definición, no afectará la base de datos, por lo que no necesitará agregar un registro antes de eliminarlo).
Una prueba de integración ejercerá la funcionalidad que utiliza múltiples componentes (como una interfaz de usuario y una base de datos), y la guía que se aplicaría a las pruebas unitarias no se aplica necesariamente a las pruebas de integración.
Como otros han mencionado en sus respuestas, lo que está haciendo no está necesariamente mal, incluso si hace cosas contrarias a alguna guía de prueba de unidad. En cambio, trate de razonar sobre lo que realmente está probando en cada método de prueba, y si encuentra que necesita múltiples componentes para satisfacer su prueba, y algunos componentes requieren una configuración previa, continúe y hágalo.
Pero, sobre todo, comprenda que hay muchos tipos de pruebas de software (pruebas unitarias, pruebas de sistema, pruebas de integración, pruebas exploratorias, etc.), y no intente aplicar la guía de un tipo a todos los demás.
fuente
Esta es exactamente la razón por la cual una de las otras pautas es usar interfaces. Si su método toma un objeto que implementa una interfaz en lugar de una implementación de clase específica, puede crear una clase que no dependa del resto de la base de código.
Otra alternativa es usar un marco burlón. Estos le permiten crear fácilmente este tipo de objetos ficticios que se pueden pasar al método que está probando. Es posible que deba crear algunas implementaciones de código auxiliar para la clase ficticia, pero aún así crea una separación de la implementación real y de lo que concierne a la prueba.
fuente
¿Entonces?
No.
Varias pruebas pueden ser independientes y todas fallan debido al mismo error. Eso es realmente normal. Muchas pruebas pueden, indirectamente, probar alguna funcionalidad común. Y todos fallan cuando se rompe la funcionalidad común. No tiene nada de malo.
Las pruebas unitarias se definen como clases precisamente para que puedan compartir fácilmente el código, como un registro ficticio común utilizado para probar la actualización y la eliminación.
fuente
Puede usar un marco simulado o usar un 'entorno' con una base de datos en memoria. La última es una clase donde puede crear todo lo que necesita para pasar la prueba, antes de que se ejecute la prueba.
Prefiero el último: los usuarios pueden ayudarlo a ingresar algunos datos para que sus pruebas se acerquen más al mundo real.
fuente