using Xunit; using Moq; using FluentAssertions; using Microsoft.Extensions.Logging; using IamService.API.Application.Commands.Organizations; using IamService.Domain.AggregatesModel.OrganizationAggregate; using IamService.Domain.Exceptions; using IamService.Domain.SeedWork; namespace IamService.UnitTests.Application.Commands.Organizations; /// /// EN: Unit tests for UpdateOrganizationCommandHandler. /// VI: Unit tests cho UpdateOrganizationCommandHandler. /// public class UpdateOrganizationCommandHandlerTests { private readonly Mock _organizationRepositoryMock; private readonly Mock> _loggerMock; private readonly Mock _unitOfWorkMock; private readonly UpdateOrganizationCommandHandler _handler; public UpdateOrganizationCommandHandlerTests() { _organizationRepositoryMock = new Mock(); _loggerMock = new Mock>(); _unitOfWorkMock = new Mock(); _unitOfWorkMock .Setup(u => u.SaveEntitiesAsync(It.IsAny())) .ReturnsAsync(true); _organizationRepositoryMock .Setup(r => r.UnitOfWork) .Returns(_unitOfWorkMock.Object); _handler = new UpdateOrganizationCommandHandler( _organizationRepositoryMock.Object, _loggerMock.Object); } [Fact] public async Task Handle_ValidCommand_UpdatesOrganization() { // Arrange var orgId = Guid.NewGuid(); var organization = Organization.Create("Old Name", "old-slug", "Old Description"); var command = new UpdateOrganizationCommand(orgId, "New Name", "New Description"); _organizationRepositoryMock .Setup(r => r.GetByIdAsync(orgId, It.IsAny())) .ReturnsAsync(organization); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert result.Should().NotBeNull(); result.Name.Should().Be("New Name"); result.Description.Should().Be("New Description"); result.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1)); } [Fact] public async Task Handle_ValidCommand_PersistsChanges() { // Arrange var orgId = Guid.NewGuid(); var organization = Organization.Create("Old Name", "old-slug"); var command = new UpdateOrganizationCommand(orgId, "New Name", null); _organizationRepositoryMock .Setup(r => r.GetByIdAsync(orgId, It.IsAny())) .ReturnsAsync(organization); // Act await _handler.Handle(command, CancellationToken.None); // Assert _organizationRepositoryMock.Verify(r => r.Update(organization), Times.Once); _unitOfWorkMock.Verify(u => u.SaveEntitiesAsync(It.IsAny()), Times.Once); } [Fact] public async Task Handle_OrganizationNotFound_ThrowsDomainException() { // Arrange var command = new UpdateOrganizationCommand(Guid.NewGuid(), "New Name", null); _organizationRepositoryMock .Setup(r => r.GetByIdAsync(It.IsAny(), It.IsAny())) .ReturnsAsync((Organization?)null); // Act var act = async () => await _handler.Handle(command, CancellationToken.None); // Assert await act.Should().ThrowAsync() .WithMessage("*not found*"); _organizationRepositoryMock.Verify(r => r.Update(It.IsAny()), Times.Never); } [Fact] public async Task Handle_WithNullDescription_UpdatesWithNullDescription() { // Arrange var orgId = Guid.NewGuid(); var organization = Organization.Create("Old Name", "old-slug", "Old Description"); var command = new UpdateOrganizationCommand(orgId, "New Name", null); _organizationRepositoryMock .Setup(r => r.GetByIdAsync(orgId, It.IsAny())) .ReturnsAsync(organization); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert result.Description.Should().BeNull(); } [Fact] public async Task Handle_CancellationRequested_PropagatesCancellation() { // Arrange var command = new UpdateOrganizationCommand(Guid.NewGuid(), "Name", null); var cts = new CancellationTokenSource(); cts.Cancel(); _organizationRepositoryMock .Setup(r => r.GetByIdAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(new OperationCanceledException()); // Act var act = async () => await _handler.Handle(command, cts.Token); // Assert await act.Should().ThrowAsync(); } }