156 lines
5.5 KiB
C#
156 lines
5.5 KiB
C#
|
|
namespace Application.Tests.Enrollments;
|
||
|
|
|
||
|
|
using Application.Enrollments.Commands;
|
||
|
|
using Domain.Entities;
|
||
|
|
using Domain.Exceptions;
|
||
|
|
using Domain.Ports.Repositories;
|
||
|
|
using Domain.Services;
|
||
|
|
using Domain.ValueObjects;
|
||
|
|
using FluentAssertions;
|
||
|
|
using NSubstitute;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
public class EnrollStudentCommandTests
|
||
|
|
{
|
||
|
|
private readonly IStudentRepository _studentRepo = Substitute.For<IStudentRepository>();
|
||
|
|
private readonly ISubjectRepository _subjectRepo = Substitute.For<ISubjectRepository>();
|
||
|
|
private readonly IEnrollmentRepository _enrollmentRepo = Substitute.For<IEnrollmentRepository>();
|
||
|
|
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
|
||
|
|
private readonly EnrollmentDomainService _enrollmentService = new();
|
||
|
|
private readonly EnrollStudentHandler _sut;
|
||
|
|
|
||
|
|
public EnrollStudentCommandTests()
|
||
|
|
{
|
||
|
|
_sut = new EnrollStudentHandler(
|
||
|
|
_studentRepo,
|
||
|
|
_subjectRepo,
|
||
|
|
_enrollmentRepo,
|
||
|
|
_enrollmentService,
|
||
|
|
_unitOfWork);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenValid_ShouldEnrollStudent()
|
||
|
|
{
|
||
|
|
var student = CreateStudent();
|
||
|
|
var subject = CreateSubjectWithProfessor(1, "Math", 1, "Prof. Smith");
|
||
|
|
|
||
|
|
_studentRepo.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
_subjectRepo.GetByIdWithProfessorAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(subject);
|
||
|
|
|
||
|
|
var command = new EnrollStudentCommand(1, 1);
|
||
|
|
var result = await _sut.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
result.Should().NotBeNull();
|
||
|
|
result.SubjectName.Should().Be("Math");
|
||
|
|
result.ProfessorName.Should().Be("Prof. Smith");
|
||
|
|
|
||
|
|
_enrollmentRepo.Received(1).Add(Arg.Any<Enrollment>());
|
||
|
|
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenStudentNotFound_ShouldThrow()
|
||
|
|
{
|
||
|
|
_studentRepo.GetByIdWithEnrollmentsAsync(999, Arg.Any<CancellationToken>())
|
||
|
|
.Returns((Student?)null);
|
||
|
|
|
||
|
|
var command = new EnrollStudentCommand(999, 1);
|
||
|
|
var act = () => _sut.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
await act.Should().ThrowAsync<StudentNotFoundException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenSubjectNotFound_ShouldThrow()
|
||
|
|
{
|
||
|
|
var student = CreateStudent();
|
||
|
|
_studentRepo.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
_subjectRepo.GetByIdWithProfessorAsync(999, Arg.Any<CancellationToken>())
|
||
|
|
.Returns((Subject?)null);
|
||
|
|
|
||
|
|
var command = new EnrollStudentCommand(1, 999);
|
||
|
|
var act = () => _sut.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
await act.Should().ThrowAsync<SubjectNotFoundException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenMaxEnrollmentsReached_ShouldThrow()
|
||
|
|
{
|
||
|
|
var student = CreateStudentWithEnrollments(3);
|
||
|
|
var subject = CreateSubjectWithProfessor(10, "Physics", 99, "New Prof");
|
||
|
|
|
||
|
|
_studentRepo.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
_subjectRepo.GetByIdWithProfessorAsync(10, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(subject);
|
||
|
|
|
||
|
|
var command = new EnrollStudentCommand(1, 10);
|
||
|
|
var act = () => _sut.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
await act.Should().ThrowAsync<MaxEnrollmentsExceededException>();
|
||
|
|
_enrollmentRepo.DidNotReceive().Add(Arg.Any<Enrollment>());
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenSameProfessor_ShouldThrow()
|
||
|
|
{
|
||
|
|
var student = CreateStudent();
|
||
|
|
var existingSubject = CreateSubjectWithProfessor(1, "Math", 1, "Prof. Smith");
|
||
|
|
AddEnrollmentToStudent(student, existingSubject);
|
||
|
|
|
||
|
|
var newSubject = CreateSubjectWithProfessor(2, "Algebra", 1, "Prof. Smith");
|
||
|
|
|
||
|
|
_studentRepo.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
_subjectRepo.GetByIdWithProfessorAsync(2, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(newSubject);
|
||
|
|
|
||
|
|
var command = new EnrollStudentCommand(1, 2);
|
||
|
|
var act = () => _sut.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
await act.Should().ThrowAsync<SameProfessorConstraintException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Student CreateStudent()
|
||
|
|
{
|
||
|
|
var student = new Student("John Doe", Email.Create("john@test.com"));
|
||
|
|
typeof(Student).GetProperty("Id")!.SetValue(student, 1);
|
||
|
|
return student;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Student CreateStudentWithEnrollments(int count)
|
||
|
|
{
|
||
|
|
var student = CreateStudent();
|
||
|
|
for (int i = 0; i < count; i++)
|
||
|
|
{
|
||
|
|
var subject = CreateSubjectWithProfessor(i + 1, $"Subject{i}", i + 1, $"Prof{i}");
|
||
|
|
AddEnrollmentToStudent(student, subject);
|
||
|
|
}
|
||
|
|
return student;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Subject CreateSubjectWithProfessor(int id, string name, int profId, string profName)
|
||
|
|
{
|
||
|
|
var professor = new Professor(profName);
|
||
|
|
typeof(Professor).GetProperty("Id")!.SetValue(professor, profId);
|
||
|
|
|
||
|
|
var subject = new Subject(name, profId);
|
||
|
|
typeof(Subject).GetProperty("Id")!.SetValue(subject, id);
|
||
|
|
typeof(Subject).GetProperty("Professor")!.SetValue(subject, professor);
|
||
|
|
|
||
|
|
return subject;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void AddEnrollmentToStudent(Student student, Subject subject)
|
||
|
|
{
|
||
|
|
var enrollment = new Enrollment(student.Id, subject.Id);
|
||
|
|
typeof(Enrollment).GetProperty("Subject")!.SetValue(enrollment, subject);
|
||
|
|
student.AddEnrollment(enrollment);
|
||
|
|
}
|
||
|
|
}
|