Skip to content

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:

  1. Configuración del Contenedor: El método Build() define la configuración específica del contenedor MongoDB, incluyendo la ruta al archivo docker-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.
  2. Creación del Contenedor: Se crea una instancia de DockerComposeCompositeService usando la configuración definida.
  3. 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);
}
}

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.

Referencias Adicionales