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 OpenSessionCommandHandler. /// VI: Unit tests cho OpenSessionCommandHandler. /// public class OpenSessionCommandHandlerTests { private readonly Mock _sessionRepoMock; private readonly Mock _tableRepoMock; private readonly Mock> _loggerMock; private readonly OpenSessionCommandHandler _handler; public OpenSessionCommandHandlerTests() { _sessionRepoMock = new Mock(); _tableRepoMock = new Mock(); _loggerMock = new Mock>(); _sessionRepoMock.Setup(r => r.UnitOfWork.SaveEntitiesAsync(It.IsAny())) .ReturnsAsync(true); _sessionRepoMock.Setup(r => r.AddAsync(It.IsAny(), It.IsAny())) .ReturnsAsync((Session s, CancellationToken _) => s); _handler = new OpenSessionCommandHandler( _sessionRepoMock.Object, _tableRepoMock.Object, _loggerMock.Object); } [Fact] public async Task Handle_WithValidCommand_ShouldCreateSessionAndOccupyTable() { // Arrange var tableId = Guid.NewGuid(); var shopId = Guid.NewGuid(); var table = new Table(shopId, "A-01", 4); _tableRepoMock.Setup(r => r.GetByIdAsync(tableId, It.IsAny())) .ReturnsAsync(table); _sessionRepoMock.Setup(r => r.GetActiveByTableAsync(tableId, It.IsAny())) .ReturnsAsync((Session?)null); var command = new OpenSessionCommand(tableId, shopId, 3); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert result.Should().NotBeNull(); result.SessionId.Should().NotBeEmpty(); table.Status.Should().Be(TableStatus.Occupied); _sessionRepoMock.Verify(r => r.AddAsync(It.IsAny(), It.IsAny()), Times.Once); _tableRepoMock.Verify(r => r.Update(table), Times.Once); _sessionRepoMock.Verify(r => r.UnitOfWork.SaveEntitiesAsync(It.IsAny()), Times.Once); } [Fact] public async Task Handle_WithNonExistentTable_ShouldThrowInvalidOperationException() { // Arrange var tableId = Guid.NewGuid(); _tableRepoMock.Setup(r => r.GetByIdAsync(tableId, It.IsAny())) .ReturnsAsync((Table?)null); var command = new OpenSessionCommand(tableId, Guid.NewGuid(), 2); // Act var action = () => _handler.Handle(command, CancellationToken.None); // Assert await action.Should().ThrowAsync() .WithMessage($"*{tableId}*not found*"); } [Fact] public async Task Handle_WithExistingActiveSession_ShouldThrowInvalidOperationException() { // Arrange var tableId = Guid.NewGuid(); var shopId = Guid.NewGuid(); var table = new Table(shopId, "A-01", 4); var existingSession = new Session(tableId, shopId, 2); _tableRepoMock.Setup(r => r.GetByIdAsync(tableId, It.IsAny())) .ReturnsAsync(table); _sessionRepoMock.Setup(r => r.GetActiveByTableAsync(tableId, It.IsAny())) .ReturnsAsync(existingSession); var command = new OpenSessionCommand(tableId, shopId, 3); // Act var action = () => _handler.Handle(command, CancellationToken.None); // Assert await action.Should().ThrowAsync() .WithMessage("*already has an active session*"); } }