197 lines
5.9 KiB
C#
197 lines
5.9 KiB
C#
|
|
namespace Application.Tests.Students;
|
||
|
|
|
||
|
|
using Application.Students.Commands;
|
||
|
|
using Application.Students.DTOs;
|
||
|
|
using Domain.Entities;
|
||
|
|
using Domain.Exceptions;
|
||
|
|
using Domain.Ports.Repositories;
|
||
|
|
using Domain.ValueObjects;
|
||
|
|
using FluentAssertions;
|
||
|
|
using NSubstitute;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
public class CreateStudentCommandTests
|
||
|
|
{
|
||
|
|
private readonly IStudentRepository _studentRepository;
|
||
|
|
private readonly IUnitOfWork _unitOfWork;
|
||
|
|
private readonly CreateStudentHandler _handler;
|
||
|
|
|
||
|
|
public CreateStudentCommandTests()
|
||
|
|
{
|
||
|
|
_studentRepository = Substitute.For<IStudentRepository>();
|
||
|
|
_unitOfWork = Substitute.For<IUnitOfWork>();
|
||
|
|
_handler = new CreateStudentHandler(_studentRepository, _unitOfWork);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WithValidData_ShouldCreateStudent()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var command = new CreateStudentCommand("John Doe", "john@example.com");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var result = await _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
result.Should().NotBeNull();
|
||
|
|
result.Name.Should().Be("John Doe");
|
||
|
|
result.Email.Should().Be("john@example.com");
|
||
|
|
result.TotalCredits.Should().Be(0);
|
||
|
|
result.Enrollments.Should().BeEmpty();
|
||
|
|
|
||
|
|
_studentRepository.Received(1).Add(Arg.Any<Student>());
|
||
|
|
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WithInvalidEmail_ShouldThrow()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var command = new CreateStudentCommand("John Doe", "invalid-email");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var act = () => _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
await act.Should().ThrowAsync<ArgumentException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WithEmptyName_ShouldThrow()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var command = new CreateStudentCommand("", "john@example.com");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var act = () => _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
await act.Should().ThrowAsync<ArgumentException>();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public class UpdateStudentCommandTests
|
||
|
|
{
|
||
|
|
private readonly IStudentRepository _studentRepository;
|
||
|
|
private readonly IUnitOfWork _unitOfWork;
|
||
|
|
private readonly UpdateStudentHandler _handler;
|
||
|
|
|
||
|
|
public UpdateStudentCommandTests()
|
||
|
|
{
|
||
|
|
_studentRepository = Substitute.For<IStudentRepository>();
|
||
|
|
_unitOfWork = Substitute.For<IUnitOfWork>();
|
||
|
|
_handler = new UpdateStudentHandler(_studentRepository, _unitOfWork);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenStudentExists_ShouldUpdateStudent()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var student = new Student("Old Name", Email.Create("old@example.com"));
|
||
|
|
SetEntityId(student, 1);
|
||
|
|
|
||
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
|
||
|
|
var command = new UpdateStudentCommand(1, "New Name", "new@example.com");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var result = await _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
result.Should().NotBeNull();
|
||
|
|
result.Name.Should().Be("New Name");
|
||
|
|
result.Email.Should().Be("new@example.com");
|
||
|
|
|
||
|
|
_studentRepository.Received(1).Update(student);
|
||
|
|
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenStudentNotFound_ShouldThrow()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(999, Arg.Any<CancellationToken>())
|
||
|
|
.Returns((Student?)null);
|
||
|
|
|
||
|
|
var command = new UpdateStudentCommand(999, "Name", "email@test.com");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var act = () => _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
await act.Should().ThrowAsync<StudentNotFoundException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WithInvalidEmail_ShouldThrow()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var student = new Student("Name", Email.Create("old@example.com"));
|
||
|
|
_studentRepository.GetByIdWithEnrollmentsAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
|
||
|
|
var command = new UpdateStudentCommand(1, "Name", "invalid");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var act = () => _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
await act.Should().ThrowAsync<ArgumentException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void SetEntityId<T>(T entity, int id) where T : class
|
||
|
|
{
|
||
|
|
typeof(T).GetProperty("Id")?.SetValue(entity, id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public class DeleteStudentCommandTests
|
||
|
|
{
|
||
|
|
private readonly IStudentRepository _studentRepository;
|
||
|
|
private readonly IUnitOfWork _unitOfWork;
|
||
|
|
private readonly DeleteStudentHandler _handler;
|
||
|
|
|
||
|
|
public DeleteStudentCommandTests()
|
||
|
|
{
|
||
|
|
_studentRepository = Substitute.For<IStudentRepository>();
|
||
|
|
_unitOfWork = Substitute.For<IUnitOfWork>();
|
||
|
|
_handler = new DeleteStudentHandler(_studentRepository, _unitOfWork);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenStudentExists_ShouldDeleteStudent()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var student = new Student("John Doe", Email.Create("john@example.com"));
|
||
|
|
_studentRepository.GetByIdAsync(1, Arg.Any<CancellationToken>())
|
||
|
|
.Returns(student);
|
||
|
|
|
||
|
|
var command = new DeleteStudentCommand(1);
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var result = await _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
result.Should().BeTrue();
|
||
|
|
_studentRepository.Received(1).Delete(student);
|
||
|
|
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public async Task Handle_WhenStudentNotFound_ShouldThrow()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
_studentRepository.GetByIdAsync(999, Arg.Any<CancellationToken>())
|
||
|
|
.Returns((Student?)null);
|
||
|
|
|
||
|
|
var command = new DeleteStudentCommand(999);
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var act = () => _handler.Handle(command, CancellationToken.None);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
await act.Should().ThrowAsync<StudentNotFoundException>();
|
||
|
|
}
|
||
|
|
}
|