feat: CAT-001 Árbol N-ario de Rubros #30
@@ -0,0 +1,167 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.Extensions.Time.Testing;
|
||||||
|
using NSubstitute;
|
||||||
|
using SIGCM2.Application.Abstractions.Persistence;
|
||||||
|
using SIGCM2.Application.Rubros.GetById;
|
||||||
|
using SIGCM2.Domain.Entities;
|
||||||
|
using SIGCM2.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace SIGCM2.Application.Tests.Rubros.GetById;
|
||||||
|
|
||||||
|
public class GetRubroByIdQueryHandlerTests
|
||||||
|
{
|
||||||
|
private static readonly FakeTimeProvider FakeTime =
|
||||||
|
new(new DateTimeOffset(2026, 4, 18, 12, 0, 0, TimeSpan.Zero));
|
||||||
|
|
||||||
|
private readonly IRubroRepository _repo = Substitute.For<IRubroRepository>();
|
||||||
|
|
||||||
|
private static DateTime UtcNow => FakeTime.GetUtcNow().UtcDateTime;
|
||||||
|
|
||||||
|
private static Rubro MakeRubro(
|
||||||
|
int id,
|
||||||
|
int? parentId = null,
|
||||||
|
bool activo = true,
|
||||||
|
int? tarifarioBaseId = null,
|
||||||
|
DateTime? fechaModificacion = null)
|
||||||
|
=> new(id, parentId, $"Rubro{id}", orden: 1, activo, tarifarioBaseId,
|
||||||
|
fechaCreacion: UtcNow, fechaModificacion);
|
||||||
|
|
||||||
|
// ── Handle_RubroExiste_ActivoPorDefecto_RetornaDto ───────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_RubroExiste_ActivoPorDefecto_RetornaDto()
|
||||||
|
{
|
||||||
|
var rubro = MakeRubro(id: 5, parentId: 2, tarifarioBaseId: 10);
|
||||||
|
_repo.GetByIdAsync(5, Arg.Any<CancellationToken>()).Returns(rubro);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var result = await handler.Handle(new GetRubroByIdQuery(Id: 5));
|
||||||
|
|
||||||
|
result.Should().NotBeNull();
|
||||||
|
result.Id.Should().Be(5);
|
||||||
|
result.Nombre.Should().Be("Rubro5");
|
||||||
|
result.ParentId.Should().Be(2);
|
||||||
|
result.Orden.Should().Be(1);
|
||||||
|
result.Activo.Should().BeTrue();
|
||||||
|
result.TarifarioBaseId.Should().Be(10);
|
||||||
|
result.FechaCreacion.Should().Be(UtcNow);
|
||||||
|
result.FechaModificacion.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_RubroNoExiste_LanzaRubroNotFoundException ────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_RubroNoExiste_LanzaRubroNotFoundException()
|
||||||
|
{
|
||||||
|
_repo.GetByIdAsync(99, Arg.Any<CancellationToken>()).Returns((Rubro?)null);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var act = () => handler.Handle(new GetRubroByIdQuery(Id: 99));
|
||||||
|
|
||||||
|
await act.Should().ThrowAsync<RubroNotFoundException>()
|
||||||
|
.WithMessage("*99*");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_RubroNotFoundException_ContienIdCorrecto ─────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_RubroNotFoundException_ContieneIdCorrecto()
|
||||||
|
{
|
||||||
|
_repo.GetByIdAsync(42, Arg.Any<CancellationToken>()).Returns((Rubro?)null);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsAsync<RubroNotFoundException>(
|
||||||
|
() => handler.Handle(new GetRubroByIdQuery(Id: 42)));
|
||||||
|
|
||||||
|
ex.Id.Should().Be(42);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_CancellationToken_SePropagaAlRepo ─────────────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_CancellationToken_SePropagaAlRepo()
|
||||||
|
{
|
||||||
|
// The handler signature accepts CancellationToken and forwards it to the repo.
|
||||||
|
// We verify the repo is called exactly once with the matching id and any token.
|
||||||
|
_repo.GetByIdAsync(7, Arg.Any<CancellationToken>()).Returns(MakeRubro(7));
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
await handler.Handle(new GetRubroByIdQuery(Id: 7));
|
||||||
|
|
||||||
|
await _repo.Received(1).GetByIdAsync(7, Arg.Any<CancellationToken>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_FechaCreacion_SeSerializaComoInstantUTC ───────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_FechaCreacion_SeSerializaComoInstantUTC()
|
||||||
|
{
|
||||||
|
var expectedUtc = new DateTime(2026, 1, 15, 8, 30, 0, DateTimeKind.Utc);
|
||||||
|
var rubro = new Rubro(3, null, "RubroUTC", 0, true, null, expectedUtc, null);
|
||||||
|
_repo.GetByIdAsync(3, Arg.Any<CancellationToken>()).Returns(rubro);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var result = await handler.Handle(new GetRubroByIdQuery(Id: 3));
|
||||||
|
|
||||||
|
result.FechaCreacion.Should().Be(expectedUtc);
|
||||||
|
result.FechaCreacion.Kind.Should().Be(DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_FechaModificacion_Null_SeRetornaNull ──────────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_FechaModificacion_Null_SeRetornaNull()
|
||||||
|
{
|
||||||
|
var rubro = MakeRubro(id: 8, fechaModificacion: null);
|
||||||
|
_repo.GetByIdAsync(8, Arg.Any<CancellationToken>()).Returns(rubro);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var result = await handler.Handle(new GetRubroByIdQuery(Id: 8));
|
||||||
|
|
||||||
|
result.FechaModificacion.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_FechaModificacion_ConValor_SeRetornaCorrecto ──────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_FechaModificacion_ConValor_SeRetornaCorrecto()
|
||||||
|
{
|
||||||
|
var fechaMod = new DateTime(2026, 3, 10, 10, 0, 0, DateTimeKind.Utc);
|
||||||
|
var rubro = MakeRubro(id: 9, fechaModificacion: fechaMod);
|
||||||
|
_repo.GetByIdAsync(9, Arg.Any<CancellationToken>()).Returns(rubro);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var result = await handler.Handle(new GetRubroByIdQuery(Id: 9));
|
||||||
|
|
||||||
|
result.FechaModificacion.Should().Be(fechaMod);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_RubroRaiz_SinParent_RetornaDtoConParentIdNull ─────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_RubroRaiz_SinParent_RetornaDtoConParentIdNull()
|
||||||
|
{
|
||||||
|
var rubro = MakeRubro(id: 1, parentId: null);
|
||||||
|
_repo.GetByIdAsync(1, Arg.Any<CancellationToken>()).Returns(rubro);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var result = await handler.Handle(new GetRubroByIdQuery(Id: 1));
|
||||||
|
|
||||||
|
result.ParentId.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Handle_RubroConTarifarioBaseId_SeRetornaCorrecto ────────────────────
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Handle_RubroConTarifarioBaseId_SeRetornaCorrecto()
|
||||||
|
{
|
||||||
|
var rubro = MakeRubro(id: 11, tarifarioBaseId: 42);
|
||||||
|
_repo.GetByIdAsync(11, Arg.Any<CancellationToken>()).Returns(rubro);
|
||||||
|
|
||||||
|
var handler = new GetRubroByIdQueryHandler(_repo);
|
||||||
|
var result = await handler.Handle(new GetRubroByIdQuery(Id: 11));
|
||||||
|
|
||||||
|
result.TarifarioBaseId.Should().Be(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user