RabbitMQ
El RabbitMQContainer
es un componente de la librería CodeDesignPlus.Net.xUnit que proporciona un contenedor Docker para ejecutar RabbitMQ, un broker de mensajería. Este componente facilita la creación de pruebas unitarias que dependen de RabbitMQ, ofreciendo un entorno de pruebas aislado y reproducible.
¿Cómo Funciona?
El RabbitMQContainer
utiliza Docker Compose
para definir y gestionar el contenedor RabbitMQ. Al inicializar una instancia de esta clase, se genera un archivo docker-compose.yml
temporal con la configuración necesaria para ejecutar el contenedor. Luego, el contenedor se inicia y se detiene automáticamente al final de la ejecución de las pruebas.
El proceso general de funcionamiento es el siguiente:
- Configuración del Contenedor: El método
Build()
define la configuración específica del contenedor RabbitMQ, incluyendo la ruta al archivodocker-compose.yml
, opciones de reinicio forzado, eliminación de contenedores huérfanos, parada al finalizar y un nombre de servicio alternativo generado dinámicamente para evitar conflictos. - Creación del Contenedor: Se crea una instancia de
DockerComposeCompositeService
usando la configuración definida. - Inicio y Detención del Contenedor: El contenedor se inicia cuando se crea una instancia de la clase
RabbitMQContainer
y se detiene automáticamente cuando la instancia se elimina, asegurando la limpieza del entorno.
Container
El RabbitMQContainer
hereda de la clase DockerCompose
, la cual proporciona la lógica base para interactuar con Docker Compose. La clase utiliza la clase DockerComposeCompositeService
de la librería Testcontainers
para iniciar y detener contenedores docker. La configuración del contenedor se define en el método Build()
que crea un archivo docker-compose.yml
con los parámetros necesarios para la ejecución del contenedor RabbitMQ. El archivo docker-compose.yml
se encuentra dentro del directorio Containers/RabbitMQContainer
.
namespace CodeDesignPlus.Net.xUnit.Containers.RabbitMQContainer;
/// <summary>/// Represents a Docker container for RabbitMQ, managed using Docker Compose./// </summary>public class RabbitMQContainer : DockerCompose{ /// <summary> /// Builds the Docker Compose service configuration for the RabbitMQ container. /// </summary> /// <returns>An <see cref="ICompositeService"/> representing the Docker Compose service.</returns> protected override ICompositeService Build() { // Define the path to the Docker Compose file. var file = Path.Combine(Directory.GetCurrentDirectory(), "Containers", "RabbitMQContainer", "docker-compose.yml");
// Configure the Docker Compose settings. var dockerCompose = new DockerComposeConfig { ComposeFilePath = new[] { file }, ForceRecreate = true, RemoveOrphans = true, StopOnDispose = true, AlternativeServiceName = "rabbitmq_" + Guid.NewGuid().ToString("N"), };
// Enable port retrieval and set the internal port and container name. this.EnableGetPort = true; this.InternalPort = 5672; this.ContainerName = $"{dockerCompose.AlternativeServiceName}-rabbitmq";
// Create and return the Docker Compose service. var compose = new DockerComposeCompositeService(base.DockerHost, dockerCompose);
return compose; }}
La clase RabbitMQCollectionFixture
se utiliza como un fixture de xUnit, que proporciona una forma de compartir el contenedor entre las pruebas de una colección.
namespace CodeDesignPlus.Net.xUnit.Containers.RabbitMQContainer;
/// <summary>/// Provides a fixture for managing a RabbitMQ container during xUnit tests./// </summary>public sealed class RabbitMQCollectionFixture : IDisposable{ /// <summary> /// The name of the collection for the RabbitMQ tests. /// </summary> public const string Collection = "RabbitMQ Collection";
/// <summary> /// Gets the RabbitMQ container instance. /// </summary> public RabbitMQContainer Container { get; }
/// <summary> /// Initializes a new instance of the <see cref="RabbitMQCollectionFixture"/> class. /// </summary> public RabbitMQCollectionFixture() { this.Container = new RabbitMQContainer();
// Wait for the RabbitMQ container to be fully initialized. Thread.Sleep(10000); }
/// <summary> /// Disposes the RabbitMQ container instance. /// </summary> public void Dispose() { this.Container.StopInstance(); }}
Ejemplo de Uso
Este ejemplo demuestra cómo usar RabbitMQContainer
para realizar pruebas de integración con RabbitMQ. La prueba verifica la conexión a una instancia de RabbitMQ usando la información de conexión proporcionada por el contenedor, y asegura que la conexión esté abierta. Este ejemplo ilustra cómo utilizar las credenciales del contenedor y la instancia de conexión para interectuar con RabbitMQ en un entorno de prueba.
using CodeDesignPlus.Net.xUnit.Containers.RabbitMQContainer;using RabbitMQ.Client;
namespace CodeDesignPlus.Net.xUnit.Test;
[Collection(RabbitMQCollectionFixture.Collection)]public class RabbitMQContainerTest(RabbitMQCollectionFixture rabbitMQCollectionFixture){ private readonly RabbitMQContainer container = rabbitMQCollectionFixture.Container;
[Fact] public async Task CheckConnectionServer() { var host = "localhost"; var port = container.Port;
var factory = new ConnectionFactory { HostName = host, Port = port, UserName = "usr_codedesignplus", Password = "Temporal1" };
// Act IConnection connection = null!;
do { try { connection = await factory.CreateConnectionAsync();
// Assert Assert.True(connection.IsOpen, "Connection should be open."); } catch { await Task.Delay(1000); }
} while (connection == null || !connection.IsOpen);
Assert.NotNull(connection); Assert.True(container.IsRunning); Assert.True(connection.IsOpen); }}
using CodeDesignPlus.Net.xUnit.Containers.RabbitMQContainer;
namespace CodeDesignPlus.Net.xUnit.Test.Definitions;
[CollectionDefinition(RabbitMQCollectionFixture.Collection)]public class RabbitMQCollectionDefinition : ICollectionFixture<RabbitMQCollectionFixture>{}
Conclusiones
- El
RabbitMQContainer
facilita la creación de pruebas unitarias que requieren una instancia de RabbitMQ. - Utiliza Docker Compose para la gestión del contenedor, proporcionando una forma sencilla de definir la configuración.
- La clase
RabbitMQCollectionFixture
permite compartir un contenedor entre todas las pruebas de una misma colección. - El uso del
RabbitMQContainer
mejora la reproducibilidad y el aislamiento de las pruebas unitarias. - El contenedor RabbitMQ se inicia automaticamente al comienzo de cada prueba y se detiene una vez termina, esto permite un ambiente de pruebas limpio.