Pruebas de integración de C# con Docker: de la A a la Z
\n\nLas pruebas de integración son una etapa crítica en el desarrollo de cualquier aplicación seria en C#. Verifican cómo los diferentes componentes del sistema (base de datos, API externas, sistemas de archivos) funcionan juntos. Sin embargo, la configuración del entorno de pruebas a menudo se convierte en un dolor de cabeza: es necesario levantar servidores reales, limpiar los datos después de las pruebas y lidiar con la inestabilidad del entorno. Docker resuelve estos problemas proporcionando contenedores ligeros, aislados y reproducibles. En este artículo, analizaremos cómo configurar las pruebas de integración de C# con Docker desde cero hasta un pipeline funcional.
\n\n¿Por qué Docker es ideal para las pruebas de integración en C#?
\n\nEl enfoque tradicional es utilizar bases de datos SQL Server locales o emuladores de servicios externos. Esto conlleva problemas:
\n- \n
- Contaminación de datos: las pruebas dejan residuos en la base de datos, afectando a otras pruebas. \n
- Incompatibilidad de entornos: en la máquina del desarrollador hay una versión del DBMS, en el servidor CI hay otra. \n
- Dificultad para la ejecución en paralelo: las pruebas entran en conflicto por los puertos y recursos. \n
Docker resuelve esto de forma sencilla: cada prueba (o grupo de pruebas) obtiene su propio contenedor aislado con la versión necesaria de la base de datos, Redis u otro servicio. Los contenedores son ligeros, se inician en segundos y se destruyen garantizadamente después de completar las pruebas. Para los desarrolladores de .NET, esto es especialmente relevante gracias a la biblioteca Testcontainers for .NET, que automatiza la gestión de contenedores directamente desde el código de las pruebas.
\n\nConfiguración del proyecto: añadiendo Docker a las pruebas de C#
\n\nPara empezar, crearemos un proyecto con pruebas de integración. Supongamos que tenemos una API web en .NET 8 que funciona con PostgreSQL. Necesitamos probar el endpoint de creación de usuario.
\n\nPaso 1: Instalación de paquetes NuGet
\nAñada los siguientes paquetes al proyecto de prueba:
\ndotnet add package Testcontainers.PostgreSql\ndotnet add package Microsoft.AspNetCore.Mvc.Testing\ndotnet add package FluentAssertions\n\nTestcontainers.PostgreSql es un envoltorio sobre el SDK de Docker que gestiona los contenedores de PostgreSQL. Microsoft.AspNetCore.Mvc.Testing permite ejecutar la aplicación web en memoria para las pruebas.
Paso 2: Creación de una clase base para las pruebas
\nCrearemos una clase abstracta que levantará el contenedor de la base de datos antes de las pruebas:
\nusing Testcontainers.PostgreSql;\nusing Xunit;\n\npublic abstract class IntegrationTestBase : IAsyncLifetime\n{\n private readonly PostgreSqlContainer _postgresContainer;\n\n protected string ConnectionString => _postgresContainer.GetConnectionString();\n\n protected IntegrationTestBase()\n {\n _postgresContainer = new PostgreSqlBuilder()\n .WithImage("postgres:16-alpine")\n .WithDatabase("testdb")\n .WithUsername("test")\n .WithPassword("test123")\n .Build();\n }\n\n public async Task InitializeAsync()\n {\n await _postgresContainer.StartAsync();\n }\n\n public async Task DisposeAsync()\n {\n await _postgresContainer.StopAsync();\n }\n}\n\nEsta clase implementa IAsyncLifetime de xUnit, lo que garantiza que el contenedor se inicie antes de todas las pruebas y se detenga después. ConnectionString se obtiene dinámicamente del contenedor; el puerto puede ser cualquier puerto libre.
Paso 3: Escribir la prueba con Testcontainers y WebApplicationFactory
\nAhora escribiremos la prueba en sí. Usaremos WebApplicationFactory para crear un cliente HTTP de prueba:
using Microsoft.AspNetCore.Mvc.Testing;\nusing FluentAssertions;\nusing System.Net.Http.Json;\n\npublic class UserApiTests : IntegrationTestBase\n{\n private readonly WebApplicationFactory<Program> _factory;\n\n public UserApiTests()\n