unit-testing - tutorial - pruebas unitarias php
¿Cuántas pruebas unitarias debo escribir por función/método? (12)
BDD (Desarrollo impulsado por el comportamiento)
Aunque todavía estoy aprendiendo, es básicamente TDD organizado / centrado en cómo se usará realmente tu software ... NO cómo se desarrollará / construirá.
Por cierto, en cuanto a si hacer múltiples aseveraciones por método de prueba, recomendaría intentarlo de ambas formas. Algunas veces verás dónde una estrategia te dejó en un aprieto y empezará a tener sentido por qué normalmente solo usas una afirmación por método.
¿Escribe una prueba por función / método, con múltiples controles en la prueba o una prueba para cada prueba?
Creo que la regla de la afirmación única es un poco demasiado estricta. En mis pruebas unitarias, trato de seguir la regla de un solo grupo de aserciones : puede usar más de una afirmación en un método de prueba, siempre y cuando haga las comprobaciones una tras otra (no cambia el estado de las aserciones). clase entre las aserciones).
Entonces, en Python, creo que una prueba como esta es correcta :
def testGetCountReturnsCountAndEnd(self):
count, endReached = self.handler.getCount()
self.assertEqual(count, 0)
self.assertTrue(endReached)
pero este debe dividirse en dos métodos de prueba:
def testGetCountReturnsOneAfterPut(self):
self.assertEqual(self.handler.getCount(), 0)
self.handler.put(''foo'')
self.assertEqual(self.handler.getCount(), 1)
Por supuesto, en el caso de grupos de aserciones largos y frecuentemente utilizados, me gusta crear métodos de aserción personalizados; estos son especialmente útiles para comparar objetos complejos.
En Java / Eclipse / JUnit utilizo dos directorios fuente (src y test) con el mismo árbol. Si tengo una src / com / mycompany / whatever / TestMePlease con métodos que valgan la pena probar (por ejemplo, deleteAll (List <?> Stuff ) arroja MyException ) creo una prueba / com / mycompany / whatever / TestMePleaseTest con métodos para probar diferentes casos de uso / escenarios:
@Test
public void deleteAllWithNullInput() { ... }
@Test(expect="MyException.class") // not sure about actual syntax here :-P
public void deleteAllWithEmptyInput() { ... }
@Test
public void deleteAllWithSingleLineInput() { ... }
@Test
public void deleteAllWithMultipleLinesInput() { ... }
Tener diferentes controles es más fácil de manejar para mí.
No obstante, dado que todas las pruebas deben ser consistentes, si quiero que mi conjunto de datos inicial permanezca inalterado, a veces tengo, por ejemplo, que crear cosas y eliminarlas en el mismo control para asegurar que las demás prueben que el conjunto de datos es prístino:
@Test
public void insertAndDelete() {
assertTrue(/*stuff does not exist yet*/);
createStuff();
assertTrue(/*stuff does exist now*/);
deleteStuff();
assertTrue(/*stuff does not exist anymore*/);
}
No sé si hay formas más inteligentes de hacerlo, para decirte la verdad ...
En general, un testcase por cheque. Cuando las pruebas se agrupan en torno a una función particular, hace que la refactorización (por ejemplo, eliminar o dividir) funcione más difícil porque las pruebas también necesitan muchos cambios. Es mucho mejor escribir las pruebas para cada tipo de comportamiento que desee de la clase. A veces, cuando se prueba un comportamiento en particular, tiene sentido tener múltiples controles por caso de prueba. Sin embargo, a medida que las pruebas se vuelven más complicadas, es más difícil cambiarlas cuando cambia algo en la clase.
Escribo al menos una prueba por método, y algunas veces más si el método requiere una configuración diferente para probar los casos buenos y los malos.
Pero NUNCA debes probar más de un método en una prueba unitaria. Reduce la cantidad de trabajo y el error al corregir tu prueba en caso de que tu API cambie.
Intento separar las pruebas de Base de datos y las Pruebas de lógica de negocios (utilizando Wikipedia como recomiendan otros aquí), ejecutar primero las bases de datos garantiza que su base de datos esté en buen estado antes de pedirle a su aplicación que juegue con ella.
Hay un buen programa de podcast con Andy Leonard sobre lo que implica y cómo hacerlo , y si desea obtener un poco más de información, he escrito una publicación en el blog sobre el tema (shameless plug; o)
Me gusta tener una prueba por cheque en un método y tener un nombre significativo para el método de prueba. Por ejemplo:
testAddUser_shouldThrowIllegalArgumentExceptionWhenUserIsNull
Sugeriría un caso de prueba para cada cheque. Mientras más mantenga atómico, ¡mejores serán sus resultados!
Mantener varias comprobaciones en una sola prueba lo ayudará a generar un informe de la cantidad de funcionalidad que necesita corregirse.
¡Mantener el estuche de prueba atómica le mostrará la calidad general!
Tengo una prueba por capacidad que ofrece la función. Sin embargo, cada prueba puede tener varias afirmaciones. El nombre de la caja de prueba indica la capacidad que se está probando.
Generalmente, para una función, tengo varias pruebas de "día soleado" y uno o algunos escenarios de "día lluvioso", dependiendo de su complejidad.
Un caso de prueba para cada control. Es más granular. Hace que sea mucho más fácil ver qué caso de prueba específico falló.
Un testcase por cheque. Si nombra el método de manera apropiada, puede proporcionar una pista valiosa sobre el problema cuando una de estas pruebas causa un error de regresión.
Una prueba por cheque y nombres súper descriptivos, por instancia:
@Test
public void userCannotVoteDownWhenScoreIsLessThanOneHundred() {
...
}
Tanto una sola afirmación como el uso de buenos nombres me dan un mejor informe cuando falla una prueba. Me gritan: "¡Rompiste ESA regla!".