using Imprink.Application.Commands.Categories; using Imprink.Application.Exceptions; using Imprink.Domain.Entities; using Imprink.Domain.Repositories; using Moq; namespace Imprink.Application.Tests; public class UpdateCategoryHandlerTests { private readonly Mock _unitOfWorkMock; private readonly Mock _categoryRepositoryMock; private readonly UpdateCategoryHandler _handler; public UpdateCategoryHandlerTests() { _unitOfWorkMock = new Mock(); _categoryRepositoryMock = new Mock(); _unitOfWorkMock.Setup(x => x.CategoryRepository) .Returns(_categoryRepositoryMock.Object); _handler = new UpdateCategoryHandler(_unitOfWorkMock.Object); } [Fact] public async Task Handle_ValidRequest_ShouldUpdateCategoryAndReturnDto() { var categoryId = Guid.NewGuid(); var parentCategoryId = Guid.NewGuid(); var createdAt = DateTime.UtcNow.AddDays(-10); var modifiedAt = DateTime.UtcNow; var existingCategory = new Category { Id = categoryId, Name = "Old Name", Description = "Old Description", ImageUrl = "old-image.jpg", SortOrder = 1, IsActive = true, ParentCategoryId = null, CreatedAt = createdAt, ModifiedAt = createdAt }; var updatedCategory = new Category { Id = categoryId, Name = "New Name", Description = "New Description", ImageUrl = "new-image.jpg", SortOrder = 2, IsActive = false, ParentCategoryId = parentCategoryId, CreatedAt = createdAt, ModifiedAt = modifiedAt }; var command = new UpdateCategoryCommand { Id = categoryId, Name = "New Name", Description = "New Description", ImageUrl = "new-image.jpg", SortOrder = 2, IsActive = false, ParentCategoryId = parentCategoryId }; _categoryRepositoryMock .Setup(x => x.GetByIdAsync(categoryId, It.IsAny())) .ReturnsAsync(existingCategory); _categoryRepositoryMock .Setup(x => x.UpdateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(updatedCategory); var result = await _handler.Handle(command, CancellationToken.None); Assert.NotNull(result); Assert.Equal(categoryId, result.Id); Assert.Equal("New Name", result.Name); Assert.Equal("New Description", result.Description); Assert.Equal("new-image.jpg", result.ImageUrl); Assert.Equal(2, result.SortOrder); Assert.False(result.IsActive); Assert.Equal(parentCategoryId, result.ParentCategoryId); Assert.Equal(createdAt, result.CreatedAt); Assert.Equal(modifiedAt, result.ModifiedAt); _unitOfWorkMock.Verify(x => x.BeginTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.CommitTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.RollbackTransactionAsync(It.IsAny()), Times.Never); _categoryRepositoryMock.Verify(x => x.GetByIdAsync(categoryId, It.IsAny()), Times.Once); _categoryRepositoryMock.Verify(x => x.UpdateAsync(It.IsAny(), It.IsAny()), Times.Once); } [Fact] public async Task Handle_CategoryNotFound_ShouldThrowNotFoundException() { // Arrange var categoryId = Guid.NewGuid(); var command = new UpdateCategoryCommand { Id = categoryId, Name = "Test Name", Description = "Test Description", SortOrder = 1, IsActive = true }; _categoryRepositoryMock .Setup(x => x.GetByIdAsync(categoryId, It.IsAny())) .ReturnsAsync((Category?)null); var exception = await Assert.ThrowsAsync( () => _handler.Handle(command, CancellationToken.None)); Assert.Equal($"Category with ID {categoryId} not found.", exception.Message); _unitOfWorkMock.Verify(x => x.BeginTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.RollbackTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.CommitTransactionAsync(It.IsAny()), Times.Never); _categoryRepositoryMock.Verify(x => x.UpdateAsync(It.IsAny(), It.IsAny()), Times.Never); } [Fact] public async Task Handle_UpdateThrowsException_ShouldRollbackTransactionAndRethrow() { var categoryId = Guid.NewGuid(); var existingCategory = new Category { Id = categoryId, Name = "Existing Name", Description = "Existing Description", SortOrder = 1, IsActive = true }; var command = new UpdateCategoryCommand { Id = categoryId, Name = "New Name", Description = "New Description", SortOrder = 2, IsActive = false }; var expectedException = new InvalidOperationException("Database error"); _categoryRepositoryMock .Setup(x => x.GetByIdAsync(categoryId, It.IsAny())) .ReturnsAsync(existingCategory); _categoryRepositoryMock .Setup(x => x.UpdateAsync(It.IsAny(), It.IsAny())) .ThrowsAsync(expectedException); var thrownException = await Assert.ThrowsAsync( () => _handler.Handle(command, CancellationToken.None)); Assert.Same(expectedException, thrownException); _unitOfWorkMock.Verify(x => x.BeginTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.RollbackTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.CommitTransactionAsync(It.IsAny()), Times.Never); } [Fact] public async Task Handle_CategoryWithNullableFields_ShouldHandleNullValues() { // Arrange var categoryId = Guid.NewGuid(); var createdAt = DateTime.UtcNow.AddDays(-5); var modifiedAt = DateTime.UtcNow; var existingCategory = new Category { Id = categoryId, Name = "Test Category", Description = "Test Description", ImageUrl = "test-image.jpg", SortOrder = 1, IsActive = true, ParentCategoryId = Guid.NewGuid(), CreatedAt = createdAt, ModifiedAt = createdAt }; var updatedCategory = new Category { Id = categoryId, Name = "Updated Category", Description = "Updated Description", ImageUrl = null, SortOrder = 5, IsActive = false, ParentCategoryId = null, CreatedAt = createdAt, ModifiedAt = modifiedAt }; var command = new UpdateCategoryCommand { Id = categoryId, Name = "Updated Category", Description = "Updated Description", ImageUrl = null, SortOrder = 5, IsActive = false, ParentCategoryId = null }; _categoryRepositoryMock .Setup(x => x.GetByIdAsync(categoryId, It.IsAny())) .ReturnsAsync(existingCategory); _categoryRepositoryMock .Setup(x => x.UpdateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(updatedCategory); // Act var result = await _handler.Handle(command, CancellationToken.None); // Assert Assert.NotNull(result); Assert.Equal(categoryId, result.Id); Assert.Equal("Updated Category", result.Name); Assert.Equal("Updated Description", result.Description); Assert.Null(result.ImageUrl); Assert.Equal(5, result.SortOrder); Assert.False(result.IsActive); Assert.Null(result.ParentCategoryId); Assert.Equal(createdAt, result.CreatedAt); Assert.Equal(modifiedAt, result.ModifiedAt); _unitOfWorkMock.Verify(x => x.BeginTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.CommitTransactionAsync(It.IsAny()), Times.Once); _unitOfWorkMock.Verify(x => x.RollbackTransactionAsync(It.IsAny()), Times.Never); } }