Cosmos.EventSourcing.Testing.Utilities
0.0.4
dotnet add package Cosmos.EventSourcing.Testing.Utilities --version 0.0.4
NuGet\Install-Package Cosmos.EventSourcing.Testing.Utilities -Version 0.0.4
<PackageReference Include="Cosmos.EventSourcing.Testing.Utilities" Version="0.0.4" />
<PackageVersion Include="Cosmos.EventSourcing.Testing.Utilities" Version="0.0.4" />
<PackageReference Include="Cosmos.EventSourcing.Testing.Utilities" />
paket add Cosmos.EventSourcing.Testing.Utilities --version 0.0.4
#r "nuget: Cosmos.EventSourcing.Testing.Utilities, 0.0.4"
#:package Cosmos.EventSourcing.Testing.Utilities@0.0.4
#addin nuget:?package=Cosmos.EventSourcing.Testing.Utilities&version=0.0.4
#tool nuget:?package=Cosmos.EventSourcing.Testing.Utilities&version=0.0.4
Cosmos.EventSourcing.Testing.Utilities
Utilidades para pruebas unitarias de command handlers en arquitecturas Event Sourcing para .NET 10.
Descripción
Este paquete provee clases abstractas para facilitar la creación de pruebas unitarias de command handlers en arquitecturas Event Sourcing, utilizando stores y senders en memoria (desconectadas de infraestructura real). Proporciona un framework de testing con sintaxis Given-When-Then para escribir tests claros y expresivos.
Instalación
dotnet add package Cosmos.EventSourcing.Testing.Utilities
Tipos de pruebas soportadas
| Clase base | Sincrónico | Asincrónico | Retorna datos |
|---|---|---|---|
CommandHandlerTest<TCommand> |
✅ | ❌ | ❌ |
CommandHandlerTest<TCommand, TResult> |
✅ | ❌ | ✅ |
CommandHandlerAsyncTest<TCommand> |
❌ | ✅ | ❌ |
CommandHandlerAsyncTest<TCommand, TResult> |
❌ | ✅ | ✅ |
¿Cuándo usar cada clase?
¿Sincrónico o Asincrónico?
- Command Handlers Sincrónicos: Son útiles cuando el handler no necesita consultar el event store para hidratar un aggregate root, es decir, cuando la lógica del comando no depende del estado previo del agregado (por ejemplo, simplemente emitir un evento sin validaciones sobre el estado actual).
- Command Handlers Asincrónicos: Son recomendados cuando el handler sí necesita hidratar el aggregate root desde el event store, ya sea para realizar validaciones, cálculos, o cualquier proceso que requiera conocer el estado actual del agregado. También son útiles si el proceso de manejo del comando involucra operaciones asincrónicas.
1. CommandHandlerTest<TCommand>
- Uso: Para command handlers SINCRÓNICOS que NO retornan datos (solo efectos colaterales, como eventos).
- Ejemplo de uso:
Pruebas de comandos que solo generan eventos, sin devolver un resultado.
public class CrearUsuarioTest : CommandHandlerTest<CrearUsuario>
{
protected override ICommandHandler<CrearUsuario> Handler =>
new CrearUsuarioHandler(eventStore);
[Fact]
public void Si_CreoUsuario_Debe_GenerarEvento()
{
// Given
var comando = new CrearUsuario(_aggregateId);
// When
When(comando);
// Then
Then(new UsuarioCreado(_aggregateId));
}
}
2. CommandHandlerTest<TCommand, TResult>
- Uso: Para command handlers SINCRÓNICOS que RETORNAN un resultado (
TResult). - Ejemplo de uso:
Pruebas donde el comando retorna un valor, además de los efectos colaterales.
public class CalcularPrecioTest : CommandHandlerTest<CalcularPrecio, decimal>
{
protected override ICommandHandler<CalcularPrecio, decimal> Handler =>
new CalcularPrecioHandler(eventStore);
[Fact]
public void Si_CalculoPrecio_Debe_RetornarValor()
{
// Given
var comando = new CalcularPrecio(_aggregateId);
// When
var resultado = When(comando);
// Then
resultado.Should().Be(100m);
Then(new PrecioCalculado(_aggregateId, 100m));
}
}
3. CommandHandlerAsyncTest<TCommand>
- Uso: Para command handlers ASINCRÓNICOS que NO retornan datos (solo efectos colaterales).
- Ejemplo de uso:
Pruebas de comandos asíncronos que solo generan eventos.
public class CrearUsuarioAsyncTest : CommandHandlerAsyncTest<CrearUsuario>
{
protected override ICommandHandlerAsync<CrearUsuario> Handler =>
new CrearUsuarioHandler(eventStore);
[Fact]
public async Task Si_CreoUsuario_Debe_GenerarEvento()
{
// Given
var comando = new CrearUsuario(_aggregateId);
// When
await WhenAsync(comando);
// Then
Then(new UsuarioCreado(_aggregateId));
}
}
4. CommandHandlerAsyncTest<TCommand, TResult>
- Uso: Para command handlers ASINCRÓNICOS que RETORNAN un resultado (
TResult). - Ejemplo de uso:
Pruebas donde el comando asíncrono retorna un valor, además de los efectos colaterales.
public class CalcularPrecioAsyncTest : CommandHandlerAsyncTest<CalcularPrecio, decimal>
{
protected override ICommandHandlerAsync<CalcularPrecio, decimal> Handler =>
new CalcularPrecioHandler(eventStore);
[Fact]
public async Task Si_CalculoPrecio_Debe_RetornarValor()
{
// Given
var comando = new CalcularPrecio(_aggregateId);
// When
var resultado = await WhenAsync(comando);
// Then
resultado.Should().Be(100m);
Then(new PrecioCalculado(_aggregateId, 100m));
}
}
Criterios para elegir la clase base
¿El handler es sincrónico o asíncrono?
- Si es asíncrono (
TaskoTask<TResult>): usa una de las variantesAsyncTest. - Si es sincrónico: usa una de las variantes
Test.
- Si es asíncrono (
¿El handler retorna un resultado?
- Si retorna un valor (no
void/Task): usa la variante conTResult. - Si no retorna valor: usa la variante sin
TResult.
- Si retorna un valor (no
Notas adicionales
- Usa los métodos
Given,When/WhenAsyncyThenpara estructurar tus pruebas siguiendo el patrón Given-When-Then. - Puedes usar
Andpara validar el estado de la raíz de agregado después de los eventos. - Los stores y senders son in-memory, ideales para pruebas unitarias rápidas y aisladas.
Requisitos
- .NET 10.0 o superior
Dependencias
- AwesomeAssertions (v9.3.0) - Librería de assertions fluidas
- xUnit (v3.2.0) - Framework de testing
- Cosmos.EventSourcing.Abstractions - Abstracciones de Event Sourcing
- Cosmos.EventDriven.Abstractions - Abstracciones de EDA
Paquetes Relacionados
- Cosmos.EventSourcing.Abstractions: Define las interfaces que se testean
- Cosmos.EventSourcing.CritterStack: Implementación de producción
Licencia
Copyright © Cosmos. Todos los derechos reservados.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- AwesomeAssertions (>= 9.3.0)
- xunit.v3.extensibility.core (>= 3.2.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.