academia/tests/Application.Tests/Enrollments/GetClassmatesQueryTests.cs

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);
}
}