Permítanme comenzar conectando fuentes: pruebas unitarias pragmáticas en Java con JUnit (también hay una versión con C # -Nunit ... pero tengo esta ... es agnóstica en su mayor parte. Recomendado).
Las buenas pruebas deben ser UN VIAJE (el acrónimo no es lo suficientemente pegajoso; tengo una copia impresa de la hoja de referencia en el libro que tuve que sacar para asegurarme de que entendí bien ...)
- Automático : la invocación de pruebas y la verificación de resultados para PASA / NO PASA deben ser automáticas
- Completo : Cobertura; Aunque los errores tienden a agruparse alrededor de ciertas regiones en el código, asegúrese de probar todas las rutas y escenarios clave. Utilice herramientas si debe conocer las regiones no probadas
- Repetible : las pruebas deben producir los mismos resultados cada vez ... siempre. Las pruebas no deben depender de parámetros incontrolables.
- Independiente : Muy importante.
- Las pruebas deben probar solo una cosa a la vez. Varias afirmaciones están bien siempre que todas estén probando una característica / comportamiento. Cuando una prueba falla, debe identificar la ubicación del problema.
- Las pruebas no deben depender entre sí : aisladas. Sin suposiciones sobre el orden de ejecución de la prueba. Asegúrese de "borrón y cuenta nueva" antes de cada prueba utilizando la configuración / desmontaje de forma adecuada
Profesional : a largo plazo, tendrá tanto código de prueba como producción (si no más), por lo tanto, siga el mismo estándar de buen diseño para su código de prueba. Métodos-clases bien factorizados con nombres que revelan la intención, sin duplicación, pruebas con buenos nombres, etc.
Las buenas pruebas también se ejecutan rápido . cualquier prueba que tarde más de medio segundo en ejecutarse ... necesita ser trabajada. Cuanto más tiempo tarde en ejecutarse el conjunto de pruebas, con menor frecuencia se ejecutará. Cuantos más cambios intente el desarrollador de escabullirse entre ejecuciones ... si algo se rompe ... llevará más tiempo descubrir qué cambio fue el culpable.
Actualización 2010-08:
- Legible : esto puede considerarse parte de Professional, sin embargo, no se puede enfatizar lo suficiente. Una prueba de fuego sería encontrar a alguien que no sea parte de su equipo y pedirle que descubra el comportamiento bajo prueba en un par de minutos. Las pruebas deben mantenerse como el código de producción, por lo que debe facilitar su lectura incluso si requiere más esfuerzo. Las pruebas deben ser simétricas (seguir un patrón) y concisas (probar un comportamiento a la vez). Utilice una convención de nomenclatura coherente (por ejemplo, el estilo TestDox). Evite abarrotar la prueba con "detalles incidentales" ... conviértase en un minimalista.
Aparte de estos, la mayoría de los otros son pautas que reducen el trabajo de bajo beneficio: por ejemplo, "No pruebe el código que no es de su propiedad" (por ejemplo, DLL de terceros). No vayas a probar getters y setters. Esté atento a la relación costo-beneficio o la probabilidad de defectos.
fuente
La mayoría de las respuestas aquí parecen abordar las mejores prácticas de pruebas unitarias en general (cuándo, dónde, por qué y qué), en lugar de escribir las pruebas en sí mismas (cómo). Dado que la pregunta parecía bastante específica en la parte "cómo", pensé en publicar esto, tomado de una presentación de "bolsa marrón" que realicé en mi empresa.
Las 5 leyes de las pruebas de escritura de Womp:
1. Utilice nombres de métodos de prueba largos y descriptivos.
2. Escriba sus pruebas en un estilo Organizar / Actuar / Afirmar .
3. Siempre proporcione un mensaje de error con sus afirmaciones.
4. Comente el motivo de la prueba : ¿cuál es el supuesto empresarial?
5. Cada prueba siempre debe revertir el estado de cualquier recurso que toque.
fuente
Tenga en cuenta estos objetivos (adaptado del libro xUnit Test Patterns de Meszaros)
Algunas cosas para facilitar esto:
No olvide que también puede hacer pruebas de integración con su marco xUnit, pero mantenga las pruebas de integración y las pruebas unitarias separadas
fuente
Las pruebas deben estar aisladas. Una prueba no debería depender de otra. Además, una prueba no debe depender de sistemas externos. En otras palabras, pruebe su código, no el código del que depende su código. Puede probar esas interacciones como parte de su integración o pruebas funcionales.
fuente
Algunas propiedades de las grandes pruebas unitarias:
Cuando una prueba falla, debería ser inmediatamente obvio dónde radica el problema. Si tiene que usar el depurador para rastrear el problema, sus pruebas no son lo suficientemente detalladas. Tener exactamente una afirmación por prueba ayuda aquí.
Cuando refactoriza, ninguna prueba debe fallar.
Las pruebas deben ejecutarse tan rápido que nunca dude en ejecutarlas.
Todas las pruebas deben pasar siempre; sin resultados no deterministas.
Las pruebas unitarias deben estar bien factorizadas, al igual que su código de producción.
@Alotor: Si está sugiriendo que una biblioteca solo debería tener pruebas unitarias en su API externa, no estoy de acuerdo. Quiero pruebas unitarias para cada clase, incluidas las clases que no expongo a llamadas externas. (Sin embargo, si siento la necesidad de escribir pruebas para métodos privados, entonces necesito refactorizar ) .
EDITAR: Hubo un comentario sobre la duplicación causada por "una afirmación por prueba". Específicamente, si tiene algún código para configurar un escenario y luego desea hacer varias afirmaciones al respecto, pero solo tiene una afirmación por prueba, puede duplicar la configuración en varias pruebas.
Yo no adopto ese enfoque. En su lugar, utilizo accesorios de prueba por escenario . He aquí un ejemplo aproximado:
fuente
Lo que busca es delinear los comportamientos de la clase bajo prueba.
La intención básica es aumentar su confianza en el comportamiento de la clase.
Esto es especialmente útil cuando se busca refactorizar su código. Martin Fowler tiene un artículo interesante sobre pruebas en su sitio web.
HTH.
salud,
Robar
fuente
La prueba debería fallar originalmente. Luego, debe escribir el código que los hace pasar, de lo contrario, corre el riesgo de escribir una prueba que tiene errores y siempre pasa.
fuente
Me gusta el acrónimo Right BICEP del libro Pragmatic Unit Testing antes mencionado :
Personalmente, creo que puede llegar bastante lejos comprobando que obtiene los resultados correctos (1 + 1 debería devolver 2 en una función de suma), probando todas las condiciones de contorno que pueda imaginar (como usar dos números de los cuales la suma es mayor que el valor máximo entero en la función de suma) y obliga a condiciones de error como fallas en la red.
fuente
Las buenas pruebas deben ser mantenibles.
No he descubierto muy bien cómo hacer esto para entornos complejos.
Todos los libros de texto comienzan a deshacerse a medida que su código base comienza a llegar a los cientos de miles o millones de líneas de código.
Una buena arquitectura puede controlar parte de la explosión de la interacción, pero inevitablemente a medida que los sistemas se vuelven más complejos, el sistema de pruebas automatizado crece con ellos.
Aquí es donde comienza a tener que lidiar con las compensaciones:
También debes decidir:
¿Dónde almacena los casos de prueba en su base de código?
Podría seguir para siempre, pero mi punto es que:
Las pruebas deben ser mantenibles.
fuente
Abordé estos principios hace un tiempo en este artículo de la revista MSDN que creo que es importante que cualquier desarrollador lea.
La forma en que defino las pruebas unitarias "buenas" es si poseen las siguientes tres propiedades:
fuente
fuente
Jay Fields tiene muchos buenos consejos sobre la redacción de pruebas unitarias y hay una publicación donde resume los consejos más importantes . Allí leerá que debe pensar críticamente sobre su contexto y juzgar si el consejo vale para usted. Aquí obtienes un montón de respuestas sorprendentes, pero tú decides cuál es la mejor para tu contexto. Pruébelos y simplemente refactorice si le huele mal.
Saludos cordiales
fuente
Nunca asuma que un método trivial de 2 líneas funcionará. Escribir una prueba unitaria rápida es la única forma de evitar que la prueba nula faltante, el signo menos fuera de lugar y / o el error de alcance sutil lo muerdan, inevitablemente cuando tiene menos tiempo para lidiar con eso que ahora.
fuente
Apoyo la respuesta de "UN VIAJE", excepto que las pruebas DEBEN depender unas de otras.
¿Por qué?
SECO: no se repita: también se aplica a las pruebas. Las dependencias de prueba pueden ayudar a 1) ahorrar tiempo de configuración, 2) ahorrar recursos de dispositivos y 3) identificar fallas. Por supuesto, solo dado que su marco de prueba admite dependencias de primera clase. De lo contrario, lo admito, son malos.
Seguimiento http://www.iam.unibe.ch/~scg/Research/JExample/
fuente
A menudo, las pruebas unitarias se basan en objetos simulados o datos simulados. Me gusta escribir tres tipos de pruebas unitarias:
El punto es evitar reproducir todo para poder probar todas las funciones.
fuente
Piense en los 2 tipos de pruebas y trátelos de manera diferente: pruebas funcionales y pruebas de rendimiento.
Utilice diferentes entradas y métricas para cada uno. Es posible que deba utilizar un software diferente para cada tipo de prueba.
fuente
Utilizo una convención de nomenclatura de prueba consistente descrita por los estándares de nomenclatura de pruebas unitarias de Roy Osherove Cada método en una clase de caso de prueba dada tiene el siguiente estilo de nomenclatura MethodUnderTest_Scenario_ExpectedResult.
La primera sección del nombre de la prueba es el nombre del método en el sistema bajo prueba.
El siguiente es el escenario específico que se está probando.
Finalmente están los resultados de ese escenario.
Cada sección usa Upper Camel Case y está delimitada por una puntuación inferior.
Encontré esto útil cuando ejecuto la prueba, la prueba se agrupa por el nombre del método bajo prueba. Y tener una convención permite a otros desarrolladores comprender la intención de la prueba.
También agrego parámetros al nombre del método si el método bajo prueba se ha sobrecargado.
fuente