Mongo
El MongoContainer
es un componente de la librería CodeDesignPlus.Net.xUnit que proporciona un contenedor Docker para ejecutar MongoDB, una base de datos NoSQL orientada a documentos. Este componente facilita la creación de pruebas unitarias que dependen de MongoDB, ofreciendo un entorno de pruebas aislado y reproducible.
¿Cómo Funciona?
El MongoContainer
utiliza Docker Compose
para definir y gestionar el contenedor MongoDB. 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 MongoDB, 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
MongoContainer
y se detiene automáticamente cuando la instancia se elimina, asegurando la limpieza del entorno.
Container
El MongoContainer
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 MongoDB. El archivo docker-compose.yml
se encuentra dentro del directorio Helpers/MongoContainer
.
namespace CodeDesignPlus.Net.xUnit.Containers.MongoContainer;
/// <summary>/// Represents a Docker container for MongoDB, managed using Docker Compose./// </summary>public class MongoContainer : DockerCompose{ /// <summary> /// Builds the Docker Compose service configuration for the MongoDB container. /// </summary> /// <returns>An <see cref="ICompositeService"/> representing the Docker Compose service.</returns> protected override ICompositeService Build() { var port = new Random().Next(27017, 28000); // Define the path to the Docker Compose file. var file = Path.Combine(Directory.GetCurrentDirectory(), "Containers", "MongoContainer", "docker-compose.yml");
// Configure the Docker Compose settings. var dockerCompose = new DockerComposeConfig { ComposeFilePath = new[] { file }, ForceRecreate = true, RemoveOrphans = true, StopOnDispose = true, AlternativeServiceName = "mongo_" + Guid.NewGuid().ToString("N"), EnvironmentNameValue = new Dictionary<string, string> { { "PORT_CUSTOM", port.ToString() }, } };
// Enable port retrieval and set the internal port and container name. this.EnableGetPort = true; this.InternalPort = port; this.ContainerName = $"{dockerCompose.AlternativeServiceName}-mongo";
// Create and return the Docker Compose service. var compose = new DockerComposeCompositeService(base.DockerHost, dockerCompose);
return compose; }}
La clase MongoCollectionFixture
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.MongoContainer;
/// <summary>/// Provides a fixture for managing a MongoDB container during xUnit tests./// </summary>public sealed class MongoCollectionFixture : IDisposable{ /// <summary> /// The name of the collection for the MongoDB tests. /// </summary> public const string Collection = "Mongo Collection";
/// <summary> /// Gets the MongoDB container instance. /// </summary> public MongoContainer Container { get; }
/// <summary> /// Initializes a new instance of the <see cref="MongoCollectionFixture"/> class. /// </summary> public MongoCollectionFixture() { this.Container = new MongoContainer(); }
/// <summary> /// Disposes the MongoDB container instance. /// </summary> public void Dispose() { this.Container.StopInstance(); }}
Ejemplo de Uso
Este ejemplo ilustra cómo usar MongoContainer para realizar pruebas de integración con MongoDB. Se conecta a una instancia de MongoDB usando la cadena de conexión proporcionada por el contenedor, se inserta un documento en una colección, y luego se consulta ese documento para verificar su existencia y contenido. La prueba muestra cómo utilizar la información de conexión del MongoContainer para interactuar con MongoDB.
using CodeDesignPlus.Net.xUnit.Containers.MongoContainer;using CodeDesignPlus.Net.xUnit.Test.Helpers;using MongoDB.Bson;using MongoDB.Bson.Serialization;using MongoDB.Bson.Serialization.Serializers;using MongoDB.Driver;
namespace CodeDesignPlus.Net.xUnit.Test;
[Collection(MongoCollectionFixture.Collection)]public class MongoContainerTest(MongoCollectionFixture mongoCollectionFixture){ private readonly MongoContainer mongoContainer = mongoCollectionFixture.Container;
[Fact] public async Task CheckConnectionServer() { BsonSerializer.TryRegisterSerializer<Guid>(new GuidSerializer(GuidRepresentation.Standard)); var host = "localhost"; var port = this.mongoContainer.Port; var databaseName = "dbtestmongo";
var connectionString = $"mongodb://{host}:{port}";
var client = new MongoClient(connectionString); var database = client.GetDatabase(databaseName);
var clientEntity = new Client() { Id = Guid.NewGuid(), Name = "Test" };
var collection = database.GetCollection<Client>(typeof(Client).Name);
await collection.InsertOneAsync(clientEntity);
var result = await collection.Find(e => e.Id == clientEntity.Id).FirstOrDefaultAsync();
Assert.NotNull(result); Assert.Equal(clientEntity.Id, result.Id); Assert.Equal(clientEntity.Name, result.Name); }}
using CodeDesignPlus.Net.xUnit.Containers.MongoContainer;
namespace CodeDesignPlus.Net.xUnit.Test.Definitions;
[CollectionDefinition(MongoCollectionFixture.Collection)]public class MongoCollectionDefinition : ICollectionFixture<MongoCollectionFixture>{}
Conclusiones
- El
MongoContainer
facilita la creación de pruebas unitarias que requieren una instancia de MongoDB. - Utiliza Docker Compose para la gestión del contenedor, proporcionando una forma sencilla de definir la configuración.
- La clase
MongoCollectionFixture
permite compartir un contenedor entre todas las pruebas de una misma colección. - El uso del
MongoContainer
mejora la reproducibilidad y el aislamiento de las pruebas unitarias. - El contenedor MongoDB se inicia automaticamente al comienzo de cada prueba y se detiene una vez termina, esto permite un ambiente de pruebas limpio.