CtrlK
BlogDocsLog inGet started
Tessl Logo

unit-testing-csharp

Implementar pruebas unitarias para proyectos C# utilizando Clean Architecture y los principios SOLID, siguiendo la metodología oficial de Adasoft con asistencia de IA. Utiliza esta habilidad siempre que el usuario solicite escribir pruebas, crear pruebas unitarias, añadir cobertura de pruebas, configurar un proyecto de pruebas, generar casos de prueba para un caso de uso o un controlador, revisar la calidad de las pruebas, corregir pruebas fallidas, simular dependencias, utilizar xUnit/FluentAssertions/NSubstitute, probar componentes Blazor con bUnit o preguntar sobre la estrategia de pruebas para cualquier proyecto C# de Adasoft. También se activa cuando el usuario menciona Red-Green-Refactor, el patrón AAA, los objetivos de cobertura de pruebas o el desarrollo basado en pruebas en un contexto C#.

100

Quality

100%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

SKILL.md
Quality
Evals
Security

Unit Testing para C# — Metodología Adasoft

Guía práctica para implementar tests unitarios en proyectos C# con Clean Architecture.


Regla de oro

Un test que siempre pasa, que no detecta fallos cuando el código cambia, o que prueba detalles de implementación en lugar de comportamiento, es peor que no tener test.

El test útil: cuando borras la lógica que valida, el test falla. Si inviertes el assert y sigue en verde, el test no sirve.


Stack tecnológico (estándar Adasoft)

LibreríaRol
xUnitFramework de tests
NSubstituteMocking de interfaces
FluentAssertionsAssertions legibles
bUnitTests de componentes Blazor

No se usan alternativas salvo decisión explícita del equipo.

Nomenclatura del proyecto de tests:

NombreProyecto.Tests/

Árbol de decisión rápido

Antes de escribir cualquier test, verificar:

  1. ¿Las dependencias entran por constructor? → Si usa new internamente: refactorizar primero
  2. ¿Los métodos dependen de interfaces (no clases concretas)? → Si recibe SqlRepo en vez de IRepo: refactorizar primero
  3. ¿La lógica de negocio está en Application/Domain? → Si vive en Infrastructure o Controller: refactorizar primero

Si alguno falla → crear tarea de refactorización en JIRA y resolverla antes de testear.

¿Qué testear por capa?

  • Domain — entidades, value objects, lógica de negocio pura
  • Application — Use Cases / Handlers (mayor prioridad)
  • Infrastructure — solo lógica no trivial, con tests de integración
  • Presentation — no se testea con unit tests (usar bUnit para componentes Blazor presentacionales)

Patrón AAA — estructura obligatoria

Todo test debe seguir AAA con comentarios explícitos:

[Fact]
public async Task Handle_ValidRequest_ReturnsChatResponse()
{
    // Arrange
    var request = new SendMessageCommand("session-1", "Hola");
    _chatRepository.GetSessionAsync("session-1").Returns(new ChatSession());
    _aiService.GenerateResponseAsync(Arg.Any<string>()).Returns("Respuesta AI");

    // Act
    var result = await _handler.Handle(request, CancellationToken.None);

    // Assert
    result.Should().NotBeNull();
    result.Content.Should().Be("Respuesta AI");
}

Señales de alerta:

  • Arrange > 15 líneas → el código tiene demasiadas dependencias
  • Más de 4-5 mocks → considerar refactorización del código bajo prueba

Convención de nombres

Metodo_Escenario_ResultadoEsperado

Ejemplos correctos:

Handle_ValidMessage_ReturnsAIResponse()
Handle_NullSession_ThrowsNotFoundException()
Handle_EmptyContent_ThrowsValidationException()
ProcessDocument_WhenFileNotFound_ReturnsError()

Reglas de mocking (NSubstitute)

// CORRECTO — mockear solo interfaces
private readonly IChatRepository _chatRepository = Substitute.For<IChatRepository>();
private readonly IAIService _aiService = Substitute.For<IAIService>();

// INCORRECTO — nunca mockear clases concretas
private readonly ChatRepository _repo = Substitute.For<ChatRepository>(); // NO

// Mock mínimo — solo configurar lo que el test realmente usa
_chatRepository.GetSessionAsync("session-1").Returns(session);

// Verify() solo cuando la llamada ES el comportamiento esperado
await _chatRepository.Received(1).SaveMessageAsync(Arg.Any<ChatMessage>());

Ciclo Red → Green → Refactor

  1. Escribir el test → debe FALLAR (si pasa sin tocar código, el test no vale)
  2. Implementar/ajustar el código → el test debe PASAR (verde)
  3. Refactorizar si aplica → el test debe seguir verde

Definition of Done (DoD) con testing

Una tarea no está terminada hasta que:

  • El código funciona
  • Los tests están escritos y en verde
  • La cobertura de la nueva funcionalidad es adecuada
  • Todos los tests existentes siguen en verde

Objetivos de cobertura por fase

FaseObjetivoQué cubre
Inicio (Ruta B)20–30% en ApplicationNo existe proyecto de test o el existente tiene una cobertura menor al 30%
Crecimiento40–60%Existe proyecto de test con una cantidad considerable de test creados, funcionales y con cobertura entre 40 y 60%
Madurez60–80%Cobertura sostenida, sin tests vacíos

La cobertura es una consecuencia, no el objetivo. Un 30% bien pensado aporta más valor que un 70% inflado con tests triviales.

No testear (no aportan valor):

  • DTOs y modelos planos sin lógica
  • Getters/setters triviales
  • Mappers automáticos sin lógica adicional
  • Clases que solo delegan sin añadir lógica

Checklist de validación (antes de dar por finalizado el test)

[ ] El test sigue el patrón AAA con comentarios explícitos
[ ] El nombre describe: Metodo_Escenario_ResultadoEsperado
[ ] Solo se mockean interfaces (no clases concretas)
[ ] Solo se configuran los métodos del mock que el test realmente usa
[ ] El test cubre: camino feliz + al menos un error + casos límite
[ ] Si borro la lógica que valida, ¿el test FALLA? ← MÁS IMPORTANTE
[ ] Si invierto el assert (BeTrue → BeFalse), ¿el test FALLA?
[ ] El bloque Arrange tiene menos de 15 líneas
[ ] El test usa menos de 5 mocks

Referencias adicionales

  • bUnit y Blazor — Testing de componentes Blazor, separación página/componente
  • Ejemplos completos — Ejemplos reales para Use Cases, repositorios y handlers
Repository
lBuitronAdasoft/TmpSkills
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.