academia/tests/Application.Tests/Students/StudentCommandsTests.cs

209 lines
6.6 KiB
C#
Raw Normal View History

namespace Application.Tests.Students;
using Application.Auth;
using Application.Students.Commands;
using Application.Students.DTOs;
using Domain.Entities;
using Domain.Exceptions;
using Domain.Ports.Repositories;
using Domain.ValueObjects;
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using NSubstitute;
using Xunit;
public class CreateStudentCommandTests
{
private readonly IStudentRepository _studentRepository;
private readonly IPasswordService _passwordService;
private readonly IUnitOfWork _unitOfWork;
private readonly IConfiguration _configuration;
private readonly CreateStudentHandler _handler;
public CreateStudentCommandTests()
{
_studentRepository = Substitute.For<IStudentRepository>();
_passwordService = Substitute.For<IPasswordService>();
_unitOfWork = Substitute.For<IUnitOfWork>();
_configuration = Substitute.For<IConfiguration>();
_passwordService.HashPassword(Arg.Any<string>()).Returns("hashed_code");
_configuration["App:BaseUrl"].Returns("http://localhost:4200");
_handler = new CreateStudentHandler(_studentRepository, _passwordService, _unitOfWork, _configuration);
}
[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.Student.Name.Should().Be("John Doe");
result.Student.Email.Should().Be("john@example.com");
result.Student.TotalCredits.Should().Be(0);
result.Student.Enrollments.Should().BeEmpty();
result.ActivationCode.Should().NotBeNullOrEmpty();
result.ActivationUrl.Should().Contain("/activate?code=");
_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>();
}
}