Programación, Tecnología y Más...

Programación, Tecnología y Más...

Como Hacer Pruebas Unitarias en .Net Core C#

Una parte esencial del desarrollo de software es  realizar pruebas a tu código(pruebas unitarias, pruebas de integración y pruebas de extremo a extremo), esto con el fin de asegurarnos que el código que escribimos funciona correctamente y cumple con  su objetivo, pero muchas veces como programadores le damos poca importancia a este tipo de pruebas,  porque no sabemos como hacerlo o lo vemos como algo no necesario, pues dejame decirte que realizar este tipo de pruebas a tu código puede ahorrarte muchos dolores de cabeza en un futuro y asegurarte que entregas un código de buena calidad.

En este artículo veremos cómo podemos realizar pruebas unitarias en net core, para este pequeño ejemplo cree un proyecto web api en net core 6 pero es aplicable a versiones anteriores, al cual le realizaremos 2 pruebas unitarias una al controlador que te permite agregar un empleado y otra prueba al servicio que contiene la lógica para agregar el empleado a la base de datos.



Para realizar las pruebas unitarias creare un nuevo proyecto NUnit

Una vez creado nuestro proyecto de pruebas unitarias instalaremos 2 paquetes nuget que nos servirán para realizar dichas pruebas.
dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.0.0
dotnet add package NSubstitute --version 4.2.2
El paquete Microsoft.EntityFrameworkCore.InMemory nos servira para poder usar EF con una base de datos en memoria, y NSubstitute como su nombre lo indica es como un sustituto(tipo mock) de datos. 

Antes empezar a escribir nuestra pruebas lo primero que debemos hacer es agregar como dependencia de proyectos el o los proyectos que estaremos usando.


Como realizaremos pruebas a nuestro controlador y a nuestro servicio crearemos 2 clases para realizar las respectivas pruebas(si son varias pruebas que vas a realizar que es lo mas comun, es buena práctica crear carpetas para cada tipo de pruebas).


Empecemos realizando las pruebas unitarias a nuestro controlador.

    public class  EmployeesControllerTest
    {
        private IEmployeeServices employeeServices;
        private EmployeeRequest employeeRequest;

        [SetUp]
        public void SetUp()
        {
            employeeServices = Substitute.For<IEmployeeServices>();
            employeeRequest = new EmployeeRequest()
            {
                Name = "Cristian",
                Age = 30
            };
        }

        [TestCase(HttpStatusCode.OK)]
        [TestCase(HttpStatusCode.InternalServerError)]
        public async Task When_Add_Employee_Controller(HttpStatusCode code)
        {
            //Arrange
            GenericResponse response = new GenericResponse()
            {
                HttpCode = code
            };

            //Act
            employeeServices.AddEmployee(employeeRequest).ReturnsForAnyArgs(response);
            EmployeesController controller = new EmployeesController(employeeServices);
            ObjectResult responseController = (ObjectResult)await controller.AddEmployee(employeeRequest);

            //Assert
            Assert.AreEqual((int)code, responseController.StatusCode.Value);
        }
    }
Para realizarle pruebas a nuestro controlador necesitamos 2 variables una que representa la interface del servicio que inyectamos en nuestro controlador y  la otra variable que representa los parámetros que recibe nuestro método post, estas variables las inicializamos en el método SetUp que Nunit nos proporciona.
En nuestro TestCase probamos la respuesta de nuestro controlador cuando la petición se realiza correctamente(devuelve un status code 200) y cuando sucede un error(devuelve status code 500). 
Si observas estas pruebas se realizan siguiendo el patrón AAA que es de lo más usado al momento de escribir pruebas ya que te ayuda a que tu prueba sea fácil de leer y comprender.

Ahora realizaremos la prueba de nuestro servicio.
public class EmployeeServicesTest
    {
        private Employee employee;
        private EmployeeRequest employeeRequest;
        private  IMapper mapper;
        [SetUp]
        public void Setup()
        {
            mapper = Substitute.For<IMapper>();
            employee = new Employee()
            {
                Id = 1,
                Name = "Cristian",
                Age = 30
            };
            employeeRequest = new EmployeeRequest()
            {
                Name = "Cristian",
                Age = 30
            };

        }

        private IServiceProvider CreateContext(string nameDB)
        {
            var services = new ServiceCollection();

            services.AddDbContext<EmployeeContext>(opt => opt.UseInMemoryDatabase(databaseName: nameDB),
                ServiceLifetime.Scoped,
                ServiceLifetime.Scoped);

            return services.BuildServiceProvider();
        }

        [TestCase(HttpStatusCode.OK)]
        [TestCase(HttpStatusCode.InternalServerError)]
        public async Task When_Add_Employee_Services(HttpStatusCode code)
        {
            //Arrange
            var nameDB = Guid.NewGuid().ToString();
            var serviceProvider = CreateContext(nameDB);

            var db = serviceProvider.GetService<EmployeeContext>();
            db.Add(employee);

            //Act
            if (code == HttpStatusCode.OK)
                mapper.Map<Employee>(employeeRequest).ReturnsForAnyArgs(employee);
            else
                mapper.Map<Employee>(employeeRequest).ThrowsForAnyArgs(x => { throw new Exception(); });

            EmployeeServices services = new EmployeeServices(db, mapper);
            var responseServices = await services.AddEmployee(employeeRequest);

            //Assert
            Assert.AreEqual(code, (responseServices.HttpCode));
        }
    }
Como en esta prueba vamos a simular la inserción de un registro usando ef usamos una base de datos en memoria, es por eso que creamos un método CreateContext que nos servirá para simular un contexto con ef de la bd que usaremos para nuestra prueba.
En nuestro TestCase de igual manera probaremos el flujo cuando el registro se inserte correctamente en la base de datos y cuando este falle por alguna razón.

Si corremos nuestras pruebas veremos que estas se ejecutan correctamente.





puedes descargar el código desde este repositorio

si quieren donarme para una café lo pueden hacer aqui.

Hasta la próxima.

Saludos desde El Salvador...



Publicar un comentario

0 Comentarios