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

259 lines
7.7 KiB
C#
Raw Normal View History

namespace Application.Tests.Students;
using Application.Students.DTOs;
using Application.Students.Queries;
using Domain.Exceptions;
using Domain.Ports.Repositories;
using FluentAssertions;
using NSubstitute;
using System.Linq.Expressions;
using Xunit;
public class GetStudentByIdQueryTests
{
private readonly IStudentRepository _studentRepository;
private readonly GetStudentByIdHandler _handler;
public GetStudentByIdQueryTests()
{
_studentRepository = Substitute.For<IStudentRepository>();
_handler = new GetStudentByIdHandler(_studentRepository);
}
[Fact]
public async Task Handle_WhenStudentExists_ShouldReturnStudentDto()
{
// Arrange
var expectedDto = new StudentDto(1, "John Doe", "john@example.com", 0, []);
_studentRepository.GetByIdProjectedAsync(
1,
Arg.Any<Expression<Func<Domain.Entities.Student, StudentDto>>>(),
Arg.Any<CancellationToken>())
.Returns(expectedDto);
var query = new GetStudentByIdQuery(1);
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.Should().NotBeNull();
result.Id.Should().Be(1);
result.Name.Should().Be("John Doe");
result.Email.Should().Be("john@example.com");
}
[Fact]
public async Task Handle_WhenStudentNotFound_ShouldThrow()
{
// Arrange
_studentRepository.GetByIdProjectedAsync<StudentDto>(
999,
Arg.Any<Expression<Func<Domain.Entities.Student, StudentDto>>>(),
Arg.Any<CancellationToken>())
.Returns((StudentDto?)null);
var query = new GetStudentByIdQuery(999);
// Act
var act = () => _handler.Handle(query, CancellationToken.None);
// Assert
await act.Should().ThrowAsync<StudentNotFoundException>();
}
[Fact]
public async Task Handle_WhenStudentHasEnrollments_ShouldReturnWithEnrollments()
{
// Arrange
var enrollments = new List<EnrollmentDto>
{
new(1, 1, "Math", 3, "Prof A", DateTime.UtcNow),
new(2, 2, "Physics", 3, "Prof B", DateTime.UtcNow)
};
var expectedDto = new StudentDto(1, "John Doe", "john@example.com", 6, enrollments);
_studentRepository.GetByIdProjectedAsync(
1,
Arg.Any<Expression<Func<Domain.Entities.Student, StudentDto>>>(),
Arg.Any<CancellationToken>())
.Returns(expectedDto);
var query = new GetStudentByIdQuery(1);
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.Enrollments.Should().HaveCount(2);
result.TotalCredits.Should().Be(6);
}
}
public class GetStudentsQueryTests
{
private readonly IStudentRepository _studentRepository;
private readonly GetStudentsHandler _handler;
public GetStudentsQueryTests()
{
_studentRepository = Substitute.For<IStudentRepository>();
_handler = new GetStudentsHandler(_studentRepository);
}
[Fact]
public async Task Handle_ShouldReturnAllStudents()
{
// Arrange
var students = new List<StudentDto>
{
new(1, "John Doe", "john@example.com", 0, []),
new(2, "Jane Doe", "jane@example.com", 3, [])
};
_studentRepository.GetAllProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentDto>>>(),
Arg.Any<CancellationToken>())
.Returns(students);
var query = new GetStudentsQuery();
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.Should().HaveCount(2);
result[0].Name.Should().Be("John Doe");
result[1].Name.Should().Be("Jane Doe");
}
[Fact]
public async Task Handle_WhenNoStudents_ShouldReturnEmptyList()
{
// Arrange
_studentRepository.GetAllProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentDto>>>(),
Arg.Any<CancellationToken>())
.Returns(new List<StudentDto>());
var query = new GetStudentsQuery();
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.Should().BeEmpty();
}
}
public class GetStudentsPagedQueryTests
{
private readonly IStudentRepository _studentRepository;
private readonly GetStudentsPagedHandler _handler;
public GetStudentsPagedQueryTests()
{
_studentRepository = Substitute.For<IStudentRepository>();
_handler = new GetStudentsPagedHandler(_studentRepository);
}
[Fact]
public async Task Handle_ShouldReturnPagedResult()
{
// Arrange
var items = new List<StudentPagedDto>
{
new(1, "John Doe", "john@example.com", 0),
new(2, "Jane Doe", "jane@example.com", 3)
};
_studentRepository.GetPagedProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentPagedDto>>>(),
null,
10,
Arg.Any<CancellationToken>())
.Returns((items, (int?)3, 5));
var query = new GetStudentsPagedQuery();
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.Items.Should().HaveCount(2);
result.NextCursor.Should().Be(3);
result.TotalCount.Should().Be(5);
result.HasNextPage.Should().BeTrue();
}
[Fact]
public async Task Handle_WithCursor_ShouldPassCursorToRepository()
{
// Arrange
_studentRepository.GetPagedProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentPagedDto>>>(),
5,
10,
Arg.Any<CancellationToken>())
.Returns((new List<StudentPagedDto>(), (int?)null, 5));
var query = new GetStudentsPagedQuery(AfterCursor: 5);
// Act
await _handler.Handle(query, CancellationToken.None);
// Assert
await _studentRepository.Received(1).GetPagedProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentPagedDto>>>(),
5,
10,
Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_WithLargePageSize_ShouldLimitTo50()
{
// Arrange
_studentRepository.GetPagedProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentPagedDto>>>(),
Arg.Any<int?>(),
50,
Arg.Any<CancellationToken>())
.Returns((new List<StudentPagedDto>(), (int?)null, 0));
var query = new GetStudentsPagedQuery(PageSize: 100);
// Act
await _handler.Handle(query, CancellationToken.None);
// Assert
await _studentRepository.Received(1).GetPagedProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentPagedDto>>>(),
null,
50,
Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_WhenNoNextPage_ShouldReturnHasNextPageFalse()
{
// Arrange
_studentRepository.GetPagedProjectedAsync(
Arg.Any<Expression<Func<Domain.Entities.Student, StudentPagedDto>>>(),
Arg.Any<int?>(),
Arg.Any<int>(),
Arg.Any<CancellationToken>())
.Returns((new List<StudentPagedDto>(), (int?)null, 2));
var query = new GetStudentsPagedQuery();
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.HasNextPage.Should().BeFalse();
result.NextCursor.Should().BeNull();
}
}