¿Cómo hacer pruebas unitarias adecuadas para raíces de agregado?
Tomemos el siguiente ejemplo:
internal class Meeting
{
public int Id { get; set; }
}
internal class DailyRoomReservation
{
private ISet<Meeting> _meetings { get; set; } = new HashSet<Meeting>();
internal void ScheduleMeeting(Meeting meeting)
{
if (_meetings.Contains(meeting)) throw new InvalidOperationException();
_meetings.Add(meeting);
}
}
Suponiendo que DailyRoomReservation
es mi agregado raíz (omití intencionalmente la mayor parte de la lógica de negocio para simplificar), ¿cómo debo probar esto? Es una buena práctica exponer solo los métodos de comando para los agregados (terminología de CQS), especialmente cuando se utiliza CQRS a gran escala. Además, no tengo necesidad comercial de exponer la propiedad _meetings
(por supuesto, probar su propósito no es una buena razón para hacerlo). Escribí las siguientes pruebas:
[Test]
internal void ScheduleNewMeeting_ShouldSucceed()
{
var uniqueMeeting = new Meeting() { Id = 1};
var dailyRoomReservation = new DailyRoomReservation();
dailyRoomReservation.ScheduleMeeting(uniqueMeeting);
}
[Test]
internal void ScheduleSameMeetingTwice_ShouldFail()
{
var meeting = new Meeting() { Id = 1};
var dailyRoomReservation = new DailyRoomReservation();
dailyRoomReservation.ScheduleMeeting(meeting);
Action scheduleMeeting = () => dailyRoomReservation.ScheduleMeeting(meeting);
scheduleMeeting.Should().ThrowExactly<InvalidOperationException>();
}
Y funcionan bastante bien, sin embargo, todavía no puedo validar en ese punto si la reunión se ha agregado realmente. ¿Cómo puedo mejorar mi enfoque?
davy.ai
Una opción para refinar el enfoque sería agregar una prueba que verifique si la reunión se ha agregado al conjunto
_meetings
después de llamar aScheduleMeeting
. Esto podría verse de la siguiente manera:Esta prueba crea una nueva reunión y una nueva instancia de
DailyRoomReservation
. Luego programa la reunión y verifica si la reunión se ha agregado al conjunto_meetings
llamando a la propiedad de solo lecturaMeetings
. Esta propiedad expone el conjunto_meetings
pero no permite modificarlo desde el exterior, por lo que aún cumple con el principio de encapsulación del estado agregado. La prueba utiliza FluentAssertions para verificar si el conjunto contiene la reunión programada recientemente.Es importante tener en cuenta que esta prueba depende de los detalles de implementación interna de
DailyRoomReservation
, que pueden cambiar en el futuro sin afectar el comportamiento público del agregado. Por lo tanto, esta prueba no debe ser la única para este escenario y debe complementarse con pruebas que verifiquen las reglas de negocio y los invariantes del agregado.