Pruebas en C#: Unit, Integration, E2E de la A a la Z

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Por qué las pruebas no son un lujo, sino una necesidad



En el mundo del desarrollo moderno en C# (.NET), la calidad del código determina no solo la velocidad de lanzamiento del producto, sino también su reputación. Errores en producción, caídas repentinas después de actualizar una dependencia o un funcionamiento incorrecto de la lógica de negocio son escenarios que se pueden evitar con un sistema de pruebas bien estructurado.



Muchos desarrolladores, especialmente los principiantes, perciben las pruebas como "trabajo extra". Sin embargo, en la práctica, las pruebas ahorran horas de depuración y refactorización. En este artículo, analizaremos tres niveles clave de pruebas en el ecosistema de C#: Unit (pruebas unitarias), Integration (pruebas de integración) y E2E (End-to-End). Verá cómo cada uno resuelve sus propios problemas, qué herramientas utilizar y cómo escribir pruebas limpias y mantenibles.



1. Pruebas Unitarias: El fundamento de la calidad



Las pruebas unitarias verifican bloques de código aislados (generalmente un método o clase) de forma independiente a las dependencias externas. En C#, este es el nivel de prueba más rápido y estable. El objetivo principal es asegurarse de que cada función funcione correctamente con diferentes datos de entrada.



Herramientas para pruebas unitarias en C#



Los frameworks más populares para .NET son xUnit (recomendado por Microsoft) y NUnit. Para la simulación de dependencias se utiliza la biblioteca Moq o FakeItEasy integrado en .NET.



Ejemplo de prueba unitaria (xUnit + Moq)



Supongamos que tenemos un servicio de cálculo de descuento que depende de un repositorio de usuarios:



public class DiscountService{    private readonly IUserRepository _userRepo;

public DiscountService(IUserRepository userRepo) { _userRepo = userRepo; }

public decimal CalculateDiscount(int userId, decimal orderTotal) { var user = _userRepo.GetById(userId); if (user.IsVip) return orderTotal * 0.2m; // 20% de descuento return orderTotal * 0.05m; // 5% de descuento }}


Prueba para este método:



public class DiscountServiceTests{    [Fact]    public void CalculateDiscount_WhenUserIsVip_Returns20Percent()    {        // Arrange        var mockRepo = new Mock<IUserRepository>();        mockRepo.Setup(repo => repo.GetById(1))                .Returns(new User { Id = 1, IsVip = true });        var service = new DiscountService(mockRepo.Object);

// Act var result = service.CalculateDiscount(1, 100m);

// Assert Assert.Equal(20m, result); }}


Importante: En las pruebas unitarias no accedemos a la base de datos real. Usamos un mock para aislar la lógica de DiscountService.



2. Pruebas de Integración: Verificación de la conexión de componentes



Las pruebas de integración verifican la interacción de varios componentes reales: base de datos, API, sistema de archivos. En .NET, para esto se suele utilizar WebApplicationFactory (para ASP.NET Core) y contenedores de prueba (Testcontainers).



Características de las pruebas de integración



  • Más lentas que las pruebas unitarias — requieren levantar infraestructura (BD, servidor HTTP).
  • Más costosas de mantener — es necesario gestionar el estado del entorno de prueba.
  • Valor — detectan problemas en la configuración, el mapeo de datos y el funcionamiento con la BD real.


Ejemplo de prueba de integración (ASP.NET Core + xUnit)



Supongamos que tenemos un controlador para trabajar con pedidos. La prueba verificará que una solicitud a la API real devuelva un JSON correcto:



public class OrdersApiTests : IClassFixture<WebApplicationFactory<Program>>{    private readonly HttpClient _client;

public OrdersApiTests(WebApplicationFactory<Program> factory) { _client = f

Blogs

Book Recommendations