From 4474e175533030c013de1dc73441d9308b81b8b6 Mon Sep 17 00:00:00 2001 From: Nguyen Quang Chien Date: Mon, 29 May 2023 21:50:26 +0700 Subject: [PATCH 1/2] add: integration test --- .../Folders/Commands/UpdateFolderTests.cs | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs diff --git a/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs b/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs new file mode 100644 index 00000000..524e1256 --- /dev/null +++ b/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs @@ -0,0 +1,131 @@ +using Application.Common.Exceptions; +using Application.Folders.Commands; +using Domain.Entities; +using FluentAssertions; +using Xunit; + +namespace Application.Tests.Integration.Folders.Commands; + +public class UpdateFolderTests : BaseClassFixture +{ + public UpdateFolderTests(CustomApiFactory apiFactory) : base(apiFactory) + { + } + + [Fact] + public async Task ShouldUpdateFolder_WhenUpdateDetailsAreValid() + { + // Arrange + var department = CreateDepartment(); + var folder = CreateFolder(); + var locker = CreateLocker(folder); + var room = CreateRoom(department, locker); + await AddAsync(room); + + var command = new UpdateFolder.Command() + { + FolderId = folder.Id, + Name = "Something else", + Capacity = 6, + Description = "ehehe", + }; + + // Act + var result = await SendAsync(command); + + // Assert + result.Id.Should().Be(folder.Id); + result.Name.Should().Be(command.Name); + result.Capacity.Should().Be(command.Capacity); + result.Description.Should().Be(command.Description); + + // Cleanup + Remove(folder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); + } + + [Fact] + public async Task ShouldThrowKeyNotFoundException_WhenThatFolderDoesNotExist() + { + // Arrange + var command = new UpdateFolder.Command() + { + FolderId = Guid.NewGuid(), + Name = "Something else", + Capacity = 6, + Description = "ehehe", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("Folder does not exist."); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenNewFolderNameHasAlreadyExistedInThatLocker() + { + // Arrange + var department = CreateDepartment(); + var duplicateNameFolder = CreateFolder(); + var folder = CreateFolder(); + var locker = CreateLocker(duplicateNameFolder, folder); + var room = CreateRoom(department, locker); + await AddAsync(room); + + var command = new UpdateFolder.Command() + { + FolderId = folder.Id, + Name = duplicateNameFolder.Name, + Capacity = 6, + Description = "ehehe", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("New folder name already exists."); + } + + [Fact] + public async Task ShouldThrowConflictException_WhenNewCapacityIsLessThanCurrentNumberOfDocuments() + { + // Arrange + var department = CreateDepartment(); + var documents = CreateNDocuments(2); + var folder = CreateFolder(documents); + folder.Capacity = 3; + var locker = CreateLocker(folder); + var room = CreateRoom(department, locker); + await AddAsync(room); + + var command = new UpdateFolder.Command() + { + FolderId = folder.Id, + Name = "Something else", + Capacity = 1, + Description = "ehehe", + }; + + // Act + var result = async () => await SendAsync(command); + + // Assert + await result.Should().ThrowAsync() + .WithMessage("New capacity cannot be less than current number of documents."); + + // Cleanup + Remove(documents[0]); + Remove(documents[1]); + Remove(folder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); + } +} \ No newline at end of file From 753f343e6121279186af764af15c08ea38e20801 Mon Sep 17 00:00:00 2001 From: kaitoz11 <43519768+kaitoz11@users.noreply.github.com> Date: Thu, 1 Jun 2023 22:23:25 +0700 Subject: [PATCH 2/2] update folder feature and fix tests --- .../Folders/Commands/UpdateFolder.cs | 70 +++++++++++++++++++ .../Folders/Commands/UpdateFolderTests.cs | 9 ++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/Application/Folders/Commands/UpdateFolder.cs b/src/Application/Folders/Commands/UpdateFolder.cs index a467f7e3..56fec760 100644 --- a/src/Application/Folders/Commands/UpdateFolder.cs +++ b/src/Application/Folders/Commands/UpdateFolder.cs @@ -1,10 +1,34 @@ +using Application.Common.Exceptions; +using Application.Common.Interfaces; using Application.Common.Models.Dtos.Physical; +using AutoMapper; +using FluentValidation; using MediatR; +using Microsoft.EntityFrameworkCore; namespace Application.Folders.Commands; public class UpdateFolder { + public class Validator : AbstractValidator + { + public Validator() + { + RuleLevelCascadeMode = CascadeMode.Stop; + + RuleFor(f => f.Name) + .NotEmpty().WithMessage("Name is required.") + .MaximumLength(64).WithMessage("Name cannot exceed 64 characters."); + + RuleFor(f => f.Description) + .MaximumLength(256).WithMessage("Description cannot exceed 256 characters."); + + RuleFor(f => f.Capacity) + .NotEmpty().WithMessage("Folder capacity is required.") + .GreaterThanOrEqualTo(1).WithMessage("Folder's capacity cannot be less than 1."); + } + } + public record Command : IRequest { public Guid FolderId { get; init; } @@ -12,4 +36,50 @@ public record Command : IRequest public string? Description { get; init; } public int Capacity { get; init; } } + + public class CommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public CommandHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(Command request, CancellationToken cancellationToken) + { + var folder = await _context.Folders + .FirstOrDefaultAsync(x => x.Id.Equals(request.FolderId), cancellationToken); + + if (folder is null) + { + throw new KeyNotFoundException("Folder does not exist."); + } + + var nameExisted = await _context.Folders.AnyAsync( x => + x.Name.Trim().ToLower().Equals(request.Name.Trim().ToLower()) + && x.Id != folder.Id + , cancellationToken); + + if (nameExisted) + { + throw new ConflictException("Folder name already exists."); + } + + if (request.Capacity < folder.NumberOfDocuments) + { + throw new ConflictException("New capacity cannot be less than current number of documents."); + } + + folder.Name = request.Name; + folder.Description = request.Description; + folder.Capacity = request.Capacity; + + var result = _context.Folders.Update(folder); + await _context.SaveChangesAsync(cancellationToken); + return _mapper.Map(result.Entity); + } + } } \ No newline at end of file diff --git a/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs b/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs index 524e1256..c3df9928 100644 --- a/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs +++ b/tests/Application.Tests.Integration/Folders/Commands/UpdateFolderTests.cs @@ -90,7 +90,14 @@ public async Task ShouldThrowConflictException_WhenNewFolderNameHasAlreadyExiste // Assert await result.Should().ThrowAsync() - .WithMessage("New folder name already exists."); + .WithMessage("Folder name already exists."); + + // Cleanup + Remove(folder); + Remove(duplicateNameFolder); + Remove(locker); + Remove(room); + Remove(await FindAsync(department.Id)); } [Fact]