unit-testing
Las reglas generales para la prueba unitaria para todos los idiomas.
Buscar..
Introducción
Al comenzar con la prueba unitaria surgen todo tipo de preguntas:
¿Qué es la prueba unitaria? ¿Qué es un SetUp y TearDown? ¿Cómo trato con las dependencias? ¿Por qué hacer pruebas de unidad en absoluto? ¿Cómo hago buenas pruebas unitarias?
Este artículo responderá todas estas preguntas, para que pueda comenzar la prueba de unidad en el idioma que desee.
Observaciones
¿Qué es la prueba unitaria?
La prueba unitaria es la prueba del código para garantizar que realiza la tarea que debe realizar. Prueba el código en el nivel más bajo posible: los métodos individuales de sus clases.
¿Qué es una unidad?
Cualquier módulo discreto de código que pueda ser probado de forma aislada. La mayoría de las clases de tiempo y sus métodos. Esta clase se conoce generalmente como la "Clase bajo prueba" (CUT) o el "Sistema bajo prueba" (SUT)
La diferencia entre las pruebas unitarias y las pruebas de integración.
La prueba de unidad es el acto de probar una sola clase en forma aislada, completamente aparte de cualquiera de sus dependencias en realidad. La prueba de integración es el acto de probar una sola clase junto con una o más de sus dependencias reales.
El SetUp y TearDown
Cuando se realiza, el método de configuración se ejecuta antes de cada prueba de unidad y el TearDown después de cada prueba.
En general, agrega todos los pasos de requisitos previos en la Configuración y todos los pasos de limpieza en el TearDown. Pero solo crea estos métodos si estos pasos son necesarios para cada prueba. Si no, que estos pasos se toman dentro de las pruebas específicas en la sección "organizar".
Como lidiar con las dependencias.
Muchas veces una clase tiene la dependencia de otras clases para ejecutar sus métodos. Para poder no depender de estas otras clases, tienes que falsificarlas. Puede crear estas clases usted mismo o usar un marco de aislamiento o de maqueta. Un marco de aislamiento es una colección de código que permite la creación fácil de clases falsas.
Clases falsas
Cualquier clase que proporcione funcionalidad suficiente para pretender que es una dependencia que necesita un CUT. Hay dos tipos de falsificaciones: Stubs y Mocks.
- Un código auxiliar: un falso que no tiene ningún efecto en la aprobación o el fracaso de la prueba y que existe únicamente para permitir que la prueba se ejecute.
- Un simulacro: un falso que realiza un seguimiento del comportamiento de la CUT y pasa o falla la prueba basada en ese comportamiento.
¿Por qué pruebas de unidad?
1. Las pruebas unitarias encontrarán errores.
Cuando escribe un conjunto completo de pruebas que definen cuál es el comportamiento esperado para una clase determinada, se revela todo lo que no se comporta como se espera.
2. La prueba de la unidad mantendrá a los insectos alejados
Realice un cambio que introduzca un error y sus pruebas pueden revelarlo la próxima vez que ejecute las pruebas.
3. La prueba de la unidad ahorra tiempo
Escribir pruebas unitarias ayuda a garantizar que su código funcione correctamente desde el principio. Las pruebas unitarias definen lo que su código debe hacer y, por lo tanto, no pasará tiempo escribiendo un código que haga cosas que no debería hacer. Nadie comprueba en el código que no cree que funcione y usted tiene que hacer algo para hacerse creer que funciona. Pasa ese tiempo para escribir pruebas unitarias.
4. La prueba de unidad le da tranquilidad.
Puede ejecutar todas esas pruebas y saber que su código funciona como se supone. Saber el estado de su código, que funciona y que puede actualizarlo y mejorarlo sin temor es algo muy bueno.
5. Las pruebas unitarias documentan el uso adecuado de una clase.
Las pruebas unitarias se convierten en ejemplos simples de cómo funciona su código, qué se espera que haga y la forma correcta de usar su código que se está probando.
Reglas generales para la prueba unitaria.
1. Para la estructura de una prueba unitaria, siga la regla AAA
Organizar:
Configurar la cosa para ser probado. Me gustan las variables, los campos y las propiedades para permitir que la prueba se ejecute así como el resultado esperado.
Actúa: llama al método que estás probando.
Afirmar:
Llame al marco de pruebas para verificar que el resultado de su "acto" sea el esperado.
2. Prueba una cosa a la vez en aislamiento
Todas las clases deben ser probadas en aislamiento. No deben depender de otra cosa que no sean las burlas y los talones. No deben depender de los resultados de otras pruebas.
3. Escribe primero las pruebas simples "justo en el medio"
Las primeras pruebas que escriba deben ser las pruebas más simples. Deben ser los que, básicamente, ilustran fácilmente la funcionalidad que intenta escribir. Luego, una vez que esas pruebas pasan, debe comenzar a escribir las pruebas más complicadas que prueban los bordes y límites de su código.
4. Escribir pruebas que prueben los bordes.
Una vez que se prueban los conceptos básicos y sabes que tu funcionalidad básica funciona, debes probar los bordes. Un buen conjunto de pruebas explorará los bordes externos de lo que podría suceder con un método determinado.
Por ejemplo:
- ¿Qué pasa si se produce un desbordamiento?
- ¿Qué pasa si los valores van a cero o por debajo?
- ¿Qué pasa si van a MaxInt o MinInt?
- ¿Qué pasa si creas un arco de 361 grados?
- ¿Qué pasa si pasas una cadena vacía?
- ¿Qué sucede si una cadena tiene un tamaño de 2 GB?
5. Prueba a través de los límites
Las pruebas unitarias deben probar ambos lados de un límite dado. Moverse a través de los límites son lugares donde su código puede fallar o funcionar de manera impredecible.
6. Si puedes, prueba todo el espectro.
Si es práctico, pruebe todo el conjunto de posibilidades para su funcionalidad. Si se trata de un tipo enumerado, pruebe la funcionalidad con cada uno de los elementos de la enumeración. Puede que no sea práctico probar todas las posibilidades, pero si puede probar todas las posibilidades, hágalo.
7. Si es posible, cubra cada ruta de código
Este también es un desafío, pero si su código está diseñado para pruebas y usted utiliza una herramienta de cobertura de códigos, puede asegurarse de que cada línea de su código esté cubierta por pruebas unitarias al menos una vez. La cobertura de cada ruta de código no garantiza que no haya errores, pero seguramente le brinda información valiosa sobre el estado de cada línea de código.
8. Escriba pruebas que revelen un error, luego corríjalo
Si encuentras un error, escribe una prueba que lo revele. Luego, puedes corregir fácilmente el error al depurar la prueba. Luego tienes una buena prueba de regresión para asegurarte de que si el error regresa por alguna razón, lo sabrás de inmediato. Es realmente fácil corregir un error cuando tiene una prueba simple y directa para ejecutar en el depurador.
Un beneficio adicional aquí es que has probado tu prueba. Debido a que ha visto fallar la prueba y luego, cuando la ha pasado, sabe que la prueba es válida porque se ha demostrado que funciona correctamente. Esto hace que sea una prueba de regresión aún mejor.
9. Hacer que cada prueba sea independiente la una de la otra.
Las pruebas nunca deben depender unas de otras. Si sus pruebas tienen que ejecutarse en un cierto orden, necesita cambiar las pruebas.
10. Escribe un aserto por prueba
Usted debe escribir una aserción por prueba. Si no puede hacer eso, refractor su código para que sus eventos SetUp y TearDown se usen para crear correctamente el entorno para que cada prueba se pueda ejecutar de forma individual.
11. Nombra tus pruebas claramente. No tengas miedo de los nombres largos
Ya que estás haciendo una aseveración por prueba, cada prueba puede terminar siendo muy específica. Por lo tanto, no tenga miedo de usar nombres largos y completos de pruebas.
Un nombre largo y completo le permite saber de inmediato qué prueba falló y exactamente qué intentaba hacer la prueba.
Las pruebas largas y claramente nombradas también pueden documentar sus pruebas. Una prueba llamada "DividedByZeroShouldThrowException" documenta exactamente lo que hace el código cuando intenta dividir por cero.
12. Prueba de que cada excepción planteada es realmente levantada
Si su código genera una excepción, escriba una prueba para asegurarse de que todas las excepciones que en realidad genere se produzcan cuando se supone que deben hacerlo.
13. Evita el uso de CheckTrue o Assert.IsTrue
Evite verificar si hay una condición booleana. Por ejemplo, en lugar de verificar si dos cosas son iguales a CheckTrue o Assert.IsTrue, use CheckEquals o Assert.IsEqual en su lugar. ¿Por qué? Debido a esto:
CheckTrue (esperado, real) Esto informará algo como: "Algunas pruebas fallaron: se esperaba que fuera cierto, pero el resultado real fue falso".
Esto no te dice nada.
CheckEquals (Esperado, Actual)
Esto le dirá algo como: "Algunas pruebas fallaron: Se esperaba 7 pero el resultado real fue 3".
Solo use CheckTrue o Assert.IsTrue cuando su valor esperado sea realmente una condición booleana.
14. Realiza tus pruebas constantemente.
Ejecute sus pruebas mientras escribe el código. Sus pruebas deben ejecutarse rápidamente, lo que le permite ejecutarlas incluso después de cambios menores. Si no puede ejecutar sus pruebas como parte de su proceso de desarrollo normal, entonces algo va mal. Se supone que las pruebas unitarias se ejecutan casi al instante. Si no lo están, probablemente es porque no los estás ejecutando de forma aislada.
15. Ejecute sus pruebas como parte de cada compilación automatizada
Del mismo modo que debería realizar la prueba mientras se desarrolla, también deben ser parte integral de su proceso de integración continua. Una prueba fallida debe significar que tu construcción está rota. No dejes que las pruebas que fallan permanezcan. Considéralo un fallo de compilación y repáralo inmediatamente.
Ejemplo de prueba unitaria simple en C #
Para este ejemplo, probaremos el método de suma de una calculadora simple.
En este ejemplo probaremos la aplicación: ApplicationToTest. Esta tiene una clase llamada Calc. Esta clase tiene un método Sum ().
El método Sum () se ve así:
public void Sum(int a, int b)
{
return a + b;
}
La prueba de unidad para probar este método se ve así:
[Testclass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
//Arrange
ApplicationToTest.Calc ClassCalc = new ApplicationToTest.Calc();
int expectedResult = 5;
//Act
int result = ClassCalc.Sum(2,3);
//Assert
Assert.AreEqual(expectedResult, result);
}
}