157 lines
5.3 KiB
C#
157 lines
5.3 KiB
C#
namespace Application.Tests.Enrollments;
|
|
|
|
using Application.Enrollments.Queries;
|
|
using Domain.Entities;
|
|
using Domain.Exceptions;
|
|
using Domain.Ports.Repositories;
|
|
using Domain.ReadModels;
|
|
using Domain.ValueObjects;
|
|
using FluentAssertions;
|
|
using NSubstitute;
|
|
using Xunit;
|
|
|
|
public class GetClassmatesQueryTests
|
|
{
|
|
private readonly IStudentRepository _studentRepository;
|
|
private readonly IEnrollmentRepository _enrollmentRepository;
|
|
private readonly GetClassmatesHandler _handler;
|
|
|
|
public GetClassmatesQueryTests()
|
|
{
|
|
_studentRepository = Substitute.For<IStudentRepository>();
|
|
_enrollmentRepository = Substitute.For<IEnrollmentRepository>();
|
|
_handler = new GetClassmatesHandler(_studentRepository, _enrollmentRepository);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_WhenStudentNotFound_ShouldThrow()
|
|
{
|
|
// Arrange
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
|
.Returns((Student?)null);
|
|
|
|
var query = new GetClassmatesQuery(1);
|
|
|
|
// Act
|
|
var act = () => _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
await act.Should().ThrowAsync<StudentNotFoundException>();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_WhenStudentHasNoEnrollments_ShouldReturnEmptyList()
|
|
{
|
|
// Arrange
|
|
var student = new Student("John Doe", Email.Create("john@test.com"));
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
|
.Returns(student);
|
|
|
|
var query = new GetClassmatesQuery(1);
|
|
|
|
// Act
|
|
var result = await _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().BeEmpty();
|
|
await _enrollmentRepository.DidNotReceive()
|
|
.GetClassmatesBatchAsync(Arg.Any<int>(), Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_WhenStudentHasEnrollments_ShouldUseBatchQuery()
|
|
{
|
|
// Arrange
|
|
var student = new Student("John Doe", Email.Create("john@test.com"));
|
|
SetEntityId(student, 1);
|
|
|
|
// Create enrollments with IDs
|
|
var enrollment1 = new Enrollment(1, 1);
|
|
var enrollment2 = new Enrollment(1, 2);
|
|
SetEntityId(enrollment1, 1);
|
|
SetEntityId(enrollment2, 2);
|
|
|
|
// Use reflection to set Subject property for name access
|
|
var subject1 = new Subject("Math", 1);
|
|
var subject2 = new Subject("Physics", 2);
|
|
SetEntityId(subject1, 1);
|
|
SetEntityId(subject2, 2);
|
|
SetNavigationProperty(enrollment1, "Subject", subject1);
|
|
SetNavigationProperty(enrollment2, "Subject", subject2);
|
|
|
|
student.AddEnrollment(enrollment1);
|
|
student.AddEnrollment(enrollment2);
|
|
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
|
.Returns(student);
|
|
|
|
var classmate1 = new ClassmateInfo(2, "Jane Doe");
|
|
var classmate2 = new ClassmateInfo(3, "Bob Smith");
|
|
|
|
var batchResult = new Dictionary<int, IReadOnlyList<ClassmateInfo>>
|
|
{
|
|
[1] = [classmate1],
|
|
[2] = [classmate2]
|
|
};
|
|
|
|
_enrollmentRepository.GetClassmatesBatchAsync(1, Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>())
|
|
.Returns(batchResult);
|
|
|
|
var query = new GetClassmatesQuery(1);
|
|
|
|
// Act
|
|
var result = await _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().HaveCount(2);
|
|
result.Should().Contain(r => r.SubjectId == 1 && r.Classmates.Any(c => c.Name == "Jane Doe"));
|
|
result.Should().Contain(r => r.SubjectId == 2 && r.Classmates.Any(c => c.Name == "Bob Smith"));
|
|
|
|
await _enrollmentRepository.Received(1)
|
|
.GetClassmatesBatchAsync(1, Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Handle_WhenNoClassmatesFound_ShouldReturnEmptyClassmatesLists()
|
|
{
|
|
// Arrange
|
|
var student = new Student("John Doe", Email.Create("john@test.com"));
|
|
SetEntityId(student, 1);
|
|
|
|
var enrollment = new Enrollment(1, 1);
|
|
SetEntityId(enrollment, 1);
|
|
var subject = new Subject("Math", 1);
|
|
SetEntityId(subject, 1);
|
|
SetNavigationProperty(enrollment, "Subject", subject);
|
|
student.AddEnrollment(enrollment);
|
|
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
|
.Returns(student);
|
|
|
|
var emptyBatchResult = new Dictionary<int, IReadOnlyList<ClassmateInfo>>();
|
|
_enrollmentRepository.GetClassmatesBatchAsync(1, Arg.Any<IEnumerable<int>>(), Arg.Any<CancellationToken>())
|
|
.Returns(emptyBatchResult);
|
|
|
|
var query = new GetClassmatesQuery(1);
|
|
|
|
// Act
|
|
var result = await _handler.Handle(query, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().HaveCount(1);
|
|
result[0].Classmates.Should().BeEmpty();
|
|
}
|
|
|
|
private static void SetEntityId<T>(T entity, int id) where T : class
|
|
{
|
|
var prop = typeof(T).GetProperty("Id");
|
|
prop?.SetValue(entity, id);
|
|
}
|
|
|
|
private static void SetNavigationProperty<T>(T entity, string propertyName, object value) where T : class
|
|
{
|
|
var prop = typeof(T).GetProperty(propertyName);
|
|
prop?.SetValue(entity, value);
|
|
}
|
|
}
|