Por lo general, las pruebas que pasan desde el principio se producen cuando uno implementa algo de una manera más general de lo que realmente se necesita para las pruebas en cuestión. Esto es bastante normal : las pruebas unitarias solo pueden proporcionar un número pequeño y finito de valores de entrada para una función determinada, pero la mayoría de las funciones se escriben para una amplia gama de posibles valores de entrada. A menudo, una implementación diseñada específicamente para los casos de prueba actuales sería más complicada que una solución más general. Si ese es el caso, sería engorroso y propenso a errores diseñar artificialmente el código de una manera que funcione solo para los casos de prueba y falle por todo lo demás.
Por ejemplo, supongamos que necesita una función para devolver el mínimo de algunos valores de una matriz determinada. Realizó una implementación, impulsada por una prueba con una matriz que contiene solo uno o dos valores. Pero en lugar de implementar esto de una manera enrevesada haciendo las comparaciones en diferentes elementos (tal vez solo los primeros dos elementos), llama a una función de mínimo de matriz de la biblioteca estándar de su ecosistema de idiomas y así hace que la implementación sea de una sola línea . Cuando ahora decide agregar una prueba con una matriz de cinco elementos, la prueba probablemente pasará desde el principio.
Pero, ¿cómo sabes que la prueba no es "verde" debido a un error en la prueba misma? Una forma simple y directa de abordar esto es haciendo una modificación temporal al sujeto bajo prueba para que la prueba falle. Por ejemplo, podría agregar intencionalmente una línea if (array.size()==5) return 123a su función. Ahora su prueba de cinco elementos fallará, así que ya sabe
- la prueba se ejecuta
- se ejecuta la llamada de afirmación en la prueba
- la llamada de afirmación en la prueba valida lo correcto
lo que debería darle cierta confianza en la prueba. Después de que haya visto que la prueba falla, deshaga la modificación y la prueba debe pasar nuevamente.
Alternativamente, puede modificar el resultado esperado de una prueba: digamos que su prueba de aprobación contiene una afirmación como
int result = Subject.UnderTest(...);
Assert.AreEqual(1,result);
entonces puede editar la prueba y reemplazar el "1" por "2". Cuando la prueba falla (como se esperaba), sabe que funciona como debería y puede deshacer el reemplazo y ver si la prueba ahora se vuelve verde. El riesgo de introducir un error en la prueba mediante este tipo de reemplazo es muy pequeño, por lo que probablemente sea aceptable para la mayoría de los casos del mundo real.
Una forma diferente, tal vez discutible, es establecer un punto de interrupción en la prueba y usar un depurador para avanzar. Eso también debería darle cierta confianza en que el código de prueba se ejecute realmente, y le da la posibilidad de validar la ruta a través de la prueba mediante inspección paso a paso. Sin embargo, se debe tener mucho cuidado de no pasar por alto los errores en una ruta de código específicamente para una prueba fallida. Para pruebas complejas, puede considerar hacer ambas cosas: hacer que falle artificialmente y usar un depurador para inspeccionarlo.