Pruebas Unitarias en .Net Core con xUnit – 1 – Lo Básico

Pruebas Unitarias en .Net Core con xUnit – 1 – Lo Básico

Esta semana veremos las bases para comenzar a hacer pruebas unitarias en .Net Core. Básicamente el “Hola Mundo” de las pruebas unitarias. Aquí te mostraré los conceptos principales con ejemplos y código real.

Si no leíste el Post anterior, Léelo. Ahí presentamos los principales conceptos que debes conocer:

Pruebas Unitarias – Conceptos Principales

Para seguir con la Solución es necesario que tengas Visual Studio. Si usas Rider o VS Code seguramente tendrás que seguir otros pasos, aunque han de ser muy similares.

La Solución

Y empezamos con la Solución de ejemplo. Una aplicación de consola para saber si un número es primo o no.

En general no nos preocuparemos por la aplicación como tal, sino únicamente por la clase externa que se utiliza para evaluar el resultado:

//Primos.cs
namespace ClaseExterna
{
    public class Primos
    {
        public bool esPrimo(int numero)
        {
            for (int contador = 2; contador < numero / 2; contador++)
            {
                if (numero % contador == 0)
                    return false;
            }
            return true;
        }
    }
}

La clase es muy sencilla. Simplemente recibe un entero, revisa si es primo y regresa un resultado de verdadero o falso.

Esta es una clase ideal para probar, ya que es una unidad de código muy clara. ¿Qué lo hace una unidad de código? Muy simple, el método hace una sola cosa, tiene una sola responsabilidad. Recuerda esto ya que es uno de los principios básicos de Código Limpio.

“Toda función o método deben de hace una sola cosa. Esto lo hace una Unidad de código.”

Agregar el Proyecto de para Pruebas de xUnit

Para agregar el proyecto el cual tendrá las pruebas unitarias, hacemos lo siguiente. Damos clic derecho sobre la solución. Seleccionamos Add (Agregar) -> New Project (Nuevo Proyecto).

En la pantalla de nuevo proyecto, buscamos xUnit, y seleccionamos xUnit Test Project (.Net Core). Asegúrate que selecciones C# o VB dependiendo del lenguaje que estés utilizando. Das clic en Next (Siguiente).

El estándar para nombrar los proyectos de pruebas unitarias suele ser [NombreDelProyecto].Tests. En este caso ponemos el nombre UnitTestBasics.Test. Damos clic en Create (Crear). El proyecto queda así:

El proyecto se crea en automático con nuestra primera prueba unitaria, completamente vacía, pero en esta podemos ver los principios básicos para que se detecte como una prueba:

//UnitTest1.cs
using System;
using Xunit; //1 - Se necesita la referencia a XUnit para poder tener el atributo Fact.

namespace UnitTestBasics.Tests
{
    public class UnitTest1
    {
        [Fact] //2 - El atributo Fact le indica al ejecutor de las pruebas 
        public void Test1()
        {
        }
    }
}

Comentarios del Código:

  1. Como Podemos ver, primero que nada, hacemos referencia a la librería xUnit. Esto nos da acceso al atributo [Fact] y a todas las funciones para validar.
  2. Las funciones que ejecutan la prueba se marcan con el atributo [Fact]. Este le indica al TestRunner que es una prueba que debe de considerar.

La Prueba Unitaria

Vamos a borrar esta prueba unitaria y creamos una desde 0 para conocer el proceso. Es muy sencillo. Simplemente damos clic en el Proyecto, damos clic en Add (Agregar) -> Class (Clase). El estándar para los nombres de las clases suele ser [NombreClaseAProbar]_Should. En este caso le ponemos el nombre [Primos]_Should. Ahora para que sea una clase de pruebas unitarias hacemos lo siguiente:

  1. Agregamos la referencia a xUnit (using Xunit).
  2. Hacemos publica la clase.

Como vamos a probar la clase Primos, la cual se encuentra en el proyecto ClaseExterna. No olvides agregar la referencia a dicho proyecto. Simplemente das clic derecho sobre el proyecto UnitTestBasics.Tests, das clic en Add (Agregar) -> Project Reference… (Referencia a Proyecto). En la siguiente pantalla selecciona el proyecto que quieres referenciar, en este caso agregamos ClaseExterna.

Ahora sí. Creamos nuestra función de prueba. El estándar para el nombre de la función es lo que se va a validar. En nuestro caso, nuestra primera prueba va a ser ValidarQueEsPrimo. Y validaremos que si enviamos un numero primo, nos regrese true.

  • Recuerda que la clase no debe de recibir ningún argumento, y que no debe de tener respuesta (void).
  • Para que el sistema pueda detectar que esta función es una prueba unitaria, recuerda agregar a la función el atributo [Fact].
//Primos_Should.cs V1
using ClaseExterna;
using Xunit;

namespace UnitTestBasics.Tests
{
    public class Primos_Should
    {
        [Fact]
        public void ValidarQueEsPrimo()
        {
            //Arrange
            var numeroAValidar = 11;
            var sut = new Primos();

            //Act
            var respuesta = sut.esPrimo(numeroAValidar);

            //Assert
            Assert.True(respuesta);
        }
    }
}

Y en los comentarios del código podemos ver los 3 pasos de la prueba unitaria:

  1. Arrange (Preparar) – Aquí creamos los datos de arranque, instanciando la clase que tiene la función que deseamos probar, y el numero a probar.
  2. Act (Ejecutar) – Ejecutamos la función EsPrimo y asignamos el resultado a la variable respuesta.
  3. Assert (Revisar) – Finalmente en la última sección nos aseguramos de que el resultado sea el esperado, o valido.
    1. Assert es una clase de xUnit que tiene muchos métodos para validar cosas. En este caso validamos que la respuesta sea True. De no ser así, se enviará una excepción y la prueba no pasará.

Recuerda que los nombres de las clases o de la solución son estándares, pero no son necesarios para que funcionen las pruebas, si quieres seguir otro estándar no debe de haber problema, solo recuerda apegarte al uno.

Esta primera prueba nos asegura que el sistema pueda detectar cuando un número es primo. Pero también tenemos que asegurarnos de que funcione bien si el número no lo es. Para esto simplemente agregamos una segunda función que valide lo contrario. La clase termina así:

//Primos_Should.cs V2
using ClaseExterna;
using Xunit;

namespace UnitTestBasics.Tests
{
    public class Primos_Should
    {
        [Fact]
        public void ValidarQueEsPrimo() 
        {
            //Arrange
            var numeroAValidar = 11;
            var sut = new Primos();

            //Act
            var respuesta = sut.esPrimo(numeroAValidar);

            //Assert
            Assert.True(respuesta);
        }

        [Fact]
        public void ValidarQueNoEsPrimo()
        {
            var numeroAValidar = 10;
            var sut = new Primos();
            var respuesta = sut.esPrimo(numeroAValidar);
            Assert.False(respuesta);
        }
    }
}

Ejecución de las Pruebas:

Y para ejecutar la prueba, simplemente damos clic derecho sobre la clase, y seleccionamos Run Test(s). Esto nos abre inmediatamente el Test Explorer en Visual Studio. También lo puedes abrir seleccionando View (Vista) -> Test Explorer (Explorador de Pruebas).

El Test Explorer es el TestRunner que más vas a usar ya que está integrado en Visual Studio. Te da una interfaz visual de todas las pruebas que encuentre en el proyecto, si ya las ejecutaste, del último resultado. La ventana se ve como en la siguiente imagen, pero la puedes adjuntar en cualquiera de los grupos de ventanas que tengas. En lo personal me gusta ponerla del lado izquierdo, detrás del Solution Explorer.

El Test Explorer es muy fácil de usar. Los 2 primeros botones te permiten ejecutar todas las pruebas, o únicamente la prueba que tienes seleccionada.

La ventana debajo de los botones te muestra de manera jerárquica todos los proyectos, Namespaces, clases y funciones prueba. También puedes ejecutar las pruebas seleccionándolas desde esta ventana. De esta manera puedes ejecutar solo las pruebas que pertenecen a una clase.

La ventana del lado derecho muestra un resumen de las pruebas seleccionadas. Si tiene errores tu prueba te mostrara la diferencia entre los valores esperados y los valores recibidos. También te indica el tiempo en el que se ejecutó la prueba. Esto te puede servir para medir ciertos tiempos de ejecución. Solo recuerda que la primera vez que ejecutas siempre toma un poco más de tiempo por la compilación. Si quieres medir tiempos vuelve a ejecutar inmediatamente la prueba y toma el segundo tiempo como referencia.

Y listo. Ya sabes cómo crear y ejecutar una prueba unitaria en Visual Studio. Trata de explorar más la pantalla y todas sus opciones. Cambia los números en la pruebas para ver cómo cambian las cosas cuando una prueba falla.

DEBUG de la Prueba Unitaria

El ultimo tip, es que puedes hacer Debug sobre una prueba unitaria. Únicamente agrega el Breakpoint en la línea donde quieres comenzar a Debugear, y da clic sobre la prueba, y en vez de seleccionar Run Test(s), selecciona Debug Test(s). El código se detendrá en cada Breakpoint que hayas puesto y podrás revisar la ejecución línea por línea. Esto te ayuda a probar tus clases sin tener que ejecutar el proyecto completo.

Resumen:

Con esto terminamos este “Hola Mundo” de las pruebas unitarias. Esto es solo una pasadita muy superficial de que son y cómo funcionan. La idea es que puedas comenzar a aplicarlas, aunque sea a un nivel muy básico. En el futuro nos adentraremos técnicas más avanzadas y conceptos adicionales como Mocks, Proxys y Code Coverage.

Si comienzas a implementar las tuyas, encontraras bloqueos que no te permitirán probar algunas cosas. Es en el proceso de aprender a solucionar dichos bloqueos donde comenzarás a aprender más patrones y mejores prácticas.

En los siguientes posts veremos cómo hacer pruebas unitarias aplicando Inversión de Control (Inversion of Control), especificamente con Inyección de Dependencia (Dependency Inyection), un patrón que te facilitará la creación de estas y hará tu código más limpio. Por lo pronto recuerda estos puntos:

  • Toda función o método deben de hacer una sola cosa. Esto lo hace una Unidad de código.
  • Si quieres empezar con pruebas unitarias en tu solución, simplemente agrega un proyecto de pruebas xUnit en la pantalla de Agregar Proyecto.
  • Los proyectos de pruebas unitarias se suelen nombrar [NombreDelProyecto].Tests.
  • Las clases que tienen las pruebas unitarias suelen llamarse. [NombreClase]_Should.
  • Las funciones que ejecutan la prueba unitaria se deben de llamar como lo que pretenden validar. Ej. ValidarQueEsPrimo().
  • Para que una clase pueda ser de pruebas unitarias debe de tener la referencia a la librería xUnit, y las funciones prueba deben de tener el atributo [Fact].
  • Para asegurar el resultado de la prueba usamos la clase Assert.
  • Para ejecutar una prueba, damos clic derecho sobre ella y seleccionamos “Run Test(s)”.
  • Si queremos debuguear desde una prueba, damos clic derecho y seleccionamos “Debug Test(s)”.
  • El Test Explorer es el TestRunner dentro de Visual Studio. Nos muestra las pruebas que ha detectado, su jerarquía, y nos permite ejecutarlas.

This Post Has One Comment

Deja un comentario

Close Menu