using FluentAssertions; using FnbEngine.API.Application.Commands; using FnbEngine.Domain.AggregatesModel.SessionAggregate; using FnbEngine.Domain.AggregatesModel.TableAggregate; using FnbEngine.Domain.SeedWork; using Microsoft.Extensions.Logging; using Moq; using Xunit; namespace FnbEngine.UnitTests.Application.Commands; /// /// EN: Unit tests for CloseSessionCommandHandler. /// VI: Unit tests cho CloseSessionCommandHandler. /// public class CloseSessionCommandHandlerTests { private readonly Mock _sessionRepoMock; private readonly Mock _tableRepoMock; private readonly Mock> _loggerMock; private readonly CloseSessionCommandHandler _handler; public CloseSessionCommandHandlerTests() { _sessionRepoMock = new Mock(); _tableRepoMock = new Mock(); _loggerMock = new Mock>(); _sessionRepoMock.Setup(r => r.UnitOfWork.SaveEntitiesAsync(It.IsAny())) .ReturnsAsync(true); _handler = new CloseSessionCommandHandler( _sessionRepoMock.Object, _tableRepoMock.Object, _loggerMock.Object); } [Fact] public async Task Handle_WithValidSession_ShouldCloseSessionAndFreeTable() { // Arrange var shopId = Guid.NewGuid(); var tableId = Guid.NewGuid(); var session = new Session(tableId, shopId, 2); var table = new Table(shopId, "A-01", 4); table.MarkAsOccupied(); _sessionRepoMock.Setup(r => r.GetByIdAsync(session.Id, It.IsAny())) .ReturnsAsync(session); _tableRepoMock.Setup(r => r.GetByIdAsync(tableId, It.IsAny())) .ReturnsAsync(table); var command = new CloseSessionCommand(session.Id); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert result.Should().BeTrue(); session.Status.Should().Be("Closed"); session.ClosedAt.Should().NotBeNull(); table.Status.Should().Be(TableStatus.Available); _sessionRepoMock.Verify(r => r.Update(session), Times.Once); _tableRepoMock.Verify(r => r.Update(table), Times.Once); } [Fact] public async Task Handle_WithNonExistentSession_ShouldThrowInvalidOperationException() { // Arrange var sessionId = Guid.NewGuid(); _sessionRepoMock.Setup(r => r.GetByIdAsync(sessionId, It.IsAny())) .ReturnsAsync((Session?)null); var command = new CloseSessionCommand(sessionId); // Act var action = () => _handler.Handle(command, CancellationToken.None); // Assert await action.Should().ThrowAsync() .WithMessage($"*{sessionId}*not found*"); } [Fact] public async Task Handle_WhenTableNotFound_ShouldStillCloseSession() { // Arrange var shopId = Guid.NewGuid(); var tableId = Guid.NewGuid(); var session = new Session(tableId, shopId, 2); _sessionRepoMock.Setup(r => r.GetByIdAsync(session.Id, It.IsAny())) .ReturnsAsync(session); _tableRepoMock.Setup(r => r.GetByIdAsync(tableId, It.IsAny())) .ReturnsAsync((Table?)null); var command = new CloseSessionCommand(session.Id); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert result.Should().BeTrue(); session.Status.Should().Be("Closed"); _tableRepoMock.Verify(r => r.Update(It.IsAny()), Times.Never); } }