Documentación de Arquitectura de Software y Testing (.NET 10 / Angular)

Manual técnico de referencia con especificación de componentes para el Módulo de Sanidad y estructuras de referencia técnica.

1. Crear un nuevo Endpoint POST en TriajeController

Implementación específica para la API de Triaje:

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\src\ZooTech.InterfaceAdapters\Modules\Module_Sanidad\Controllers\TriajeController.cs
[HttpPost("nuevo-endpoint")]
[ProducesResponseType(typeof(GeneralResponseDTO<TriajeResponse>), StatusCodes.Status200OK)]
public async Task<IActionResult> CreateNuevoEndpoint([FromBody] TriajeRequest request)
{
    var behaviorPipeline = _createTriajeBehaviorPipelineFactory.Create();

    var command = new CreateTriajeCommand
    {
        VacunoId = request.VacunoId,
        TipoPesoCode = request.TipoPesoCode,
        PesoKg = request.PesoKg,
        Observaciones = request.Observaciones,
        EncargadoUsuarioId = request.EncargadoUsuarioId,
        FechaHora = request.FechaHora
    };

    var result = await behaviorPipeline.Handle(command, CancellationToken.None);

    return Ok(GeneralResponseDTO<TriajeResponse>.CreateSuccess(
        new TriajeResponse(result.Id, result.Codigo, result.FechaHora, result.VacunoId, result.TipoPesoCode, result.PesoKg, result.Observaciones, result.EstadoRegistroCode, result.EncargadoUsuarioId, result.CreatedAt),
        "Registro creado exitosamente"
    ));
}
// Especificación del Patrón (Sintaxis de Referencia)
[HttpPost("custom-route")]
public async Task<IActionResult> CustomAction([FromBody] CustomRequest request)
{
    var pipeline = _pipelineFactory.Create();
    var command = new CustomCommand { Property = request.Property };
    var result = await pipeline.Handle(command, CancellationToken.None);
    return Ok(GeneralResponseDTO<CustomResponse>.CreateSuccess(result));
}

2. Mostrar la columna Observaciones en el Listado (Campo Existente)

Mapeo específico del campo real observaciones:

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\src\ZooTech.Infrastructure\Persistence\Entities\triaje.cs
[StringLength(150)]
[Unicode(false)]
public string? observaciones { get; set; }
Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-frontend-1\src\app\modules\sanidad\presentation\triaje-report\reporte-listado-grafico-general\reporte-listado-grafico-general.html
<th>Observaciones</th>
<td>{{ t.observaciones || '-' }}</td>
// Especificación del Patrón (Mapeo de Referencia)
// Entity Property
public string? PropertyName { get; set; }

// HTML Cell Rendering
<th>HeaderName</th>
<td>{{ item.propertyName }}</td>

3. Pruebas Unitarias de Endpoints CRUD (TriajeController)

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\tests\Unit\ZooTech.InterfaceAdapters.UnitTests\Modules\Module_Sanidad\Controllers\TriajeControllerTests.cs
[Fact]
public async Task Create_MapsRequestAndReturnsCreatedAtAction()
{
    CreateTriajeCommand? captured = null;
    var controller = CreateController(createFactory: new CreateFactory(command =>
    {
        captured = command;
        return Task.FromResult(new CreateTriajeOutput(9, "TRI009", Now, command.VacunoId, command.TipoPesoCode!, command.PesoKg, command.Observaciones, "ACTIVO", command.EncargadoUsuarioId, Now));
    }));
    var request = new TriajeRequest(5, "CONTROL", 120m, "Obs", 10, Now.AddDays(-1));

    var result = await controller.Create(request);

    var createdResult = Assert.IsType<CreatedAtActionResult>(result);
    Assert.Equal(5, captured?.VacunoId);
}
// Especificación del Patrón (Estructura Test Fact)
[Fact]
public async Task ControllerMethod_ReturnsExpectedResult()
{
    var controller = CreateController(factory: new MockFactory(req => Task.FromResult(new MockOutput())));
    var result = await controller.TargetMethod(new MockRequest());
    Assert.IsType<OkObjectResult>(result);
}

4. Pruebas Unitarias para Endpoints de Gráficos e Historial

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\tests\Unit\ZooTech.InterfaceAdapters.UnitTests\Modules\Module_Sanidad\Controllers\TriajeControllerTests.cs
[Fact]
public async Task GetHistorialGeneral_MapsDatesAndReturnsOk()
{
    GetHistorialGeneralCommand? captured = null;
    var controller = CreateController(historialGeneralFactory: new HistorialGeneralFactory(command =>
    {
        captured = command;
        return Task.FromResult(new GetHistorialGeneralOutput(new[] { new HistorialTriajeItemOutput(1, Now, "CONTROL", 120m) }));
    }));

    var result = await controller.GetHistorialGeneral("2026-07-01", "2026-07-31");

    Assert.IsType<OkObjectResult>(result);
    Assert.Equal("2026-07-01", captured?.FechaDesde);
}
// Especificación del Patrón (Filtro de Consulta)
[Fact]
public async Task GetQuery_PassesFiltersCorrectly()
{
    CustomQuery? captured = null;
    var controller = CreateController(queryFactory: new QueryFactory(q => { captured = q; return Task.FromResult(new QueryOutput()); }));
    var result = await controller.QueryEndpoint("filter");
    Assert.Equal("filter", captured?.Filter);
}

5. Pruebas Unitarias para Exportación a PDF y Excel

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\tests\Unit\ZooTech.InterfaceAdapters.UnitTests\Modules\Module_Sanidad\Controllers\TriajeControllerTests.cs
[Fact]
public async Task GeneratePdf_MapsFiltersAndReturnsFile()
{
    GenerateTriajesPdfQuery? captured = null;
    var controller = CreateController(pdfFactory: new PdfFactory(query =>
    {
        captured = query;
        return Task.FromResult(new GenerateTriajesPdfOutput(new byte[] { 1 }, "application/pdf", "triajes.pdf"));
    }));

    var result = await controller.GeneratePdf("2026-07-22", "2026-07-01", "2026-07-31", "TRI", "Luna", "CONTROL", "120", 5, CancellationToken.None);

    var fileResult = Assert.IsType<FileContentResult>(result);
    Assert.Equal("application/pdf", fileResult.ContentType);
}
// Especificación del Patrón (Test Descarga Archivo)
[Fact]
public async Task ExportFile_ReturnsFileContentResult()
{
    var controller = CreateController(fileFactory: new FileFactory(_ => Task.FromResult(new FileOutput(new byte[] { 1 }, "application/pdf", "doc.pdf"))));
    var result = await controller.ExportEndpoint();
    var fileResult = Assert.IsType<FileContentResult>(result);
    Assert.Equal("application/pdf", fileResult.ContentType);
}

6. Mandados Rápidos de Código (Tareas en Vivo)

Mandado A: Filtro por Rango de Pesos (LINQ)

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\src\ZooTech.Infrastructure\Persistence\Modules\Module_Sanidad\Repositories\TriajeRepository.cs
if (pesoDesde.HasValue)
    query = query.Where(t => t.peso_kg >= pesoDesde.Value);

if (pesoHasta.HasValue)
    query = query.Where(t => t.peso_kg <= pesoHasta.Value);

Mandado B: Regla de Validación de Peso Máximo (FluentValidation)

Ruta: C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\src\ZooTech.Application\Modules\Module_Sanidad\Validators\CreateTriajeValidator.cs
RuleFor(x => x.PesoKg)
    .InclusiveBetween(1m, 1500m)
    .WithMessage("El peso registrado debe estar entre 1 kg y 1500 kg.");
// Especificación del Patrón (Validation Pattern)
RuleFor(x => x.PropertyName)
    .InclusiveBetween(min, max)
    .WithMessage("Validation Error Message");

7. Ejecución de las Suites por Consola (.NET CLI)

Ruta: Consola PowerShell
# 1. Pruebas de Aplicacion (244 tests)
cd "C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\tests\Unit\ZooTech.Application.UnitTests"
dotnet test

# 2. Pruebas de InterfaceAdapters (47 tests)
cd "C:\Users\juan9\OneDrive\Desktop\ciclo 7\construncionII\zootech-backend\tests\Unit\ZooTech.InterfaceAdapters.UnitTests"
dotnet test