using FluentAssertions; using FnbEngine.API.Application.Commands; 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 CreateTableCommandHandler. /// VI: Unit tests cho CreateTableCommandHandler. /// public class CreateTableCommandHandlerTests { private readonly Mock _repoMock; private readonly Mock> _loggerMock; private readonly CreateTableCommandHandler _handler; public CreateTableCommandHandlerTests() { _repoMock = new Mock(); _loggerMock = new Mock>(); _repoMock.Setup(r => r.UnitOfWork.SaveEntitiesAsync(It.IsAny())) .ReturnsAsync(true); _repoMock.Setup(r => r.AddAsync(It.IsAny(), It.IsAny())) .ReturnsAsync((Table t, CancellationToken _) => t); _handler = new CreateTableCommandHandler(_repoMock.Object, _loggerMock.Object); } [Fact] public async Task Handle_WithValidCommand_ShouldCreateTableAndReturnId() { // Arrange var shopId = Guid.NewGuid(); _repoMock.Setup(r => r.GetByNumberAsync(shopId, "A-01", It.IsAny())) .ReturnsAsync((Table?)null); var command = new CreateTableCommand(shopId, "A-01", 4, "Main Hall"); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert result.Should().NotBeNull(); result.TableId.Should().NotBeEmpty(); _repoMock.Verify(r => r.AddAsync(It.IsAny
(), It.IsAny()), Times.Once); _repoMock.Verify(r => r.UnitOfWork.SaveEntitiesAsync(It.IsAny()), Times.Once); } [Fact] public async Task Handle_WithDuplicateTableNumber_ShouldThrowInvalidOperationException() { // Arrange var shopId = Guid.NewGuid(); var existingTable = new Table(shopId, "A-01", 4); _repoMock.Setup(r => r.GetByNumberAsync(shopId, "A-01", It.IsAny())) .ReturnsAsync(existingTable); var command = new CreateTableCommand(shopId, "A-01", 6); // Act var action = () => _handler.Handle(command, CancellationToken.None); // Assert await action.Should().ThrowAsync() .WithMessage("*already exists*"); } [Fact] public async Task Handle_WithHourlyRate_ShouldSetHourlyRateOnTable() { // Arrange var shopId = Guid.NewGuid(); _repoMock.Setup(r => r.GetByNumberAsync(shopId, "K-01", It.IsAny())) .ReturnsAsync((Table?)null); Table? capturedTable = null; _repoMock.Setup(r => r.AddAsync(It.IsAny
(), It.IsAny())) .Callback((t, _) => capturedTable = t) .ReturnsAsync((Table t, CancellationToken _) => t); var command = new CreateTableCommand(shopId, "K-01", 4, HourlyRate: 100_000m); // Act await _handler.Handle(command, CancellationToken.None); // Assert capturedTable.Should().NotBeNull(); capturedTable!.HourlyRate.Should().Be(100_000m); } [Fact] public async Task Handle_WithZeroHourlyRate_ShouldNotSetHourlyRate() { // Arrange var shopId = Guid.NewGuid(); _repoMock.Setup(r => r.GetByNumberAsync(shopId, "K-02", It.IsAny())) .ReturnsAsync((Table?)null); Table? capturedTable = null; _repoMock.Setup(r => r.AddAsync(It.IsAny
(), It.IsAny())) .Callback((t, _) => capturedTable = t) .ReturnsAsync((Table t, CancellationToken _) => t); var command = new CreateTableCommand(shopId, "K-02", 4, HourlyRate: 0); // Act await _handler.Handle(command, CancellationToken.None); // Assert capturedTable.Should().NotBeNull(); capturedTable!.HourlyRate.Should().Be(0); } }