From 3cb6ef841aa760bdb17625222e58de4d127d1855 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:22:33 +0500 Subject: [PATCH 01/13] ShouldRemoveReaderByIdAsync -> FAIL --- .../ReaderServiceTests.Logic.RemoveById.cs | 53 +++++++++++++++++++ .../Foundations/Readers/IReaderService.cs | 1 + .../Foundations/Readers/ReaderService.cs | 3 ++ 3 files changed, 57 insertions(+) create mode 100644 LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs new file mode 100644 index 0000000..9ea2289 --- /dev/null +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs @@ -0,0 +1,53 @@ +//----------------------------------------------------------- +// Copyright (c) Coalition of Good-Hearted Engineers +// Free To Use To Build Reliable Library Management Solutions +//----------------------------------------------------------- + +using FluentAssertions; +using LibraryManagement.Api.Models.Foundations.Readers; +using Moq; + +namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers +{ + public partial class ReaderServiceTests + { + [Fact] + public async Task ShouldRemoveReaderByIdAsync() + { + // given + Guid randomId = Guid.NewGuid(); + Guid inputReaderId = randomId; + Reader randomReader = CreateRandomReader(); + Reader storageReader = randomReader; + Reader expectedInputReader = storageReader; + Reader deletedReader = expectedInputReader; + Reader expectedReader = deletedReader; + + this.storageBrokerMock.Setup(broker => + broker.SelectReaderByIdAsync(inputReaderId)) + .ReturnsAsync(storageReader); + + this.storageBrokerMock.Setup(broker => + broker.DeleteReaderAsync(expectedInputReader)) + .ReturnsAsync(deletedReader); + + // when + Reader actualReader = + await this.readerService.RemoveReaderByIdAsync(randomId); + + // then + actualReader.Should().BeEquivalentTo(expectedReader); + + this.storageBrokerMock.Verify(broker => + broker.SelectReaderByIdAsync(inputReaderId), + Times.Once); + + this.storageBrokerMock.Verify(broker => + broker.DeleteReaderAsync(expectedInputReader), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + } + } +} diff --git a/LibraryManagement.Api/Services/Foundations/Readers/IReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/IReaderService.cs index 0c1fea4..2dd6ebb 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/IReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/IReaderService.cs @@ -13,5 +13,6 @@ public interface IReaderService IQueryable RetrieveAllReaders(); ValueTask RetrieveReaderByIdAsync(Guid readerId); ValueTask ModifyReaderAsync(Reader reader); + ValueTask RemoveReaderByIdAsync(Guid readerId); } } diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 12769f2..16438ca 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -58,5 +58,8 @@ public ValueTask ModifyReaderAsync(Reader reader) => return await this.storageBroker.UpdateReaderAsync(reader); }); + + public ValueTask RemoveReaderByIdAsync(Guid readerId) => + throw new NotImplementedException(); } } From 837d51ab2985f852d1463276d9fa6f1c78fbffe7 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:27:15 +0500 Subject: [PATCH 02/13] ShouldRemoveReaderByIdAsync -> PASS --- .../Readers/ReaderServiceTests.Logic.RemoveById.cs | 3 ++- .../Services/Foundations/Readers/ReaderService.cs | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs index 9ea2289..cbaba0f 100644 --- a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Logic.RemoveById.cs @@ -4,6 +4,7 @@ //----------------------------------------------------------- using FluentAssertions; +using Force.DeepCloner; using LibraryManagement.Api.Models.Foundations.Readers; using Moq; @@ -21,7 +22,7 @@ public async Task ShouldRemoveReaderByIdAsync() Reader storageReader = randomReader; Reader expectedInputReader = storageReader; Reader deletedReader = expectedInputReader; - Reader expectedReader = deletedReader; + Reader expectedReader = deletedReader.DeepClone(); this.storageBrokerMock.Setup(broker => broker.SelectReaderByIdAsync(inputReaderId)) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 16438ca..966f842 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -59,7 +59,14 @@ public ValueTask ModifyReaderAsync(Reader reader) => return await this.storageBroker.UpdateReaderAsync(reader); }); - public ValueTask RemoveReaderByIdAsync(Guid readerId) => - throw new NotImplementedException(); + public async ValueTask RemoveReaderByIdAsync(Guid readerId) + { + Reader maybeReader = + await this.storageBroker.SelectReaderByIdAsync(readerId); + + ValidateStorageReader(maybeReader, readerId); + + return await this.storageBroker.DeleteReaderAsync(maybeReader); + } } } From 1a6f81070e51778770c260e94263824b3217f846 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:29:27 +0500 Subject: [PATCH 03/13] ShouldThrowValidationExceptionOnRemoveIfIdIsInvalidAndLogItAsync -> FAIL --- ...aderServiceTests.Validations.RemoveById.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs new file mode 100644 index 0000000..1e2d385 --- /dev/null +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs @@ -0,0 +1,59 @@ +//----------------------------------------------------------- +// Copyright (c) Coalition of Good-Hearted Engineers +// Free To Use To Build Reliable Library Management Solutions +//----------------------------------------------------------- + +using FluentAssertions; +using LibraryManagement.Api.Models.Foundations.Readers; +using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; +using Moq; + +namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers +{ + public partial class ReaderServiceTests + { + [Fact] + public async Task ShouldThrowValidationExceptionOnRemoveIfIdIsInvalidAndLogItAsync() + { + // given + Guid invalidReaderId = Guid.Empty; + + var invalidReaderException = new InvalidReaderException(); + + invalidReaderException.AddData( + key: nameof(Reader.ReaderId), + values: "Id is required"); + + var expectedReaderValidationException = + new ReaderValidationException(invalidReaderException); + + // when + ValueTask removeReaderById = + this.readerService.RemoveReaderByIdAsync(invalidReaderId); + + ReaderValidationException actualReaderValidationException = + await Assert.ThrowsAsync(() => + removeReaderById.AsTask()); + + // then + actualReaderValidationException.Should() + .BeEquivalentTo(expectedReaderValidationException); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedReaderValidationException))), + Times.Once); + + this.storageBrokerMock.Verify(broker => + broker.SelectReaderByIdAsync(It.IsAny()), + Times.Never); + + this.storageBrokerMock.Verify(broker => + broker.DeleteReaderAsync(It.IsAny()), + Times.Never); + + this.loggingBrokerMock.VerifyNoOtherCalls(); + this.storageBrokerMock.VerifyNoOtherCalls(); + } + } +} From 78cbbcceca9b3f334aec786cb8318dabb7e3bc0f Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:32:01 +0500 Subject: [PATCH 04/13] ShouldThrowValidationExceptionOnRemoveIfIdIsInvalidAndLogItAsync -> PASS --- .../Foundations/Readers/ReaderService.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 966f842..555f5d0 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -6,6 +6,7 @@ using LibraryManagement.Api.Brokers.Loggings; using LibraryManagement.Api.Brokers.Storages; using LibraryManagement.Api.Models.Foundations.Readers; +using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; namespace LibraryManagement.Api.Services.Foundations.Readers { @@ -61,12 +62,24 @@ public ValueTask ModifyReaderAsync(Reader reader) => public async ValueTask RemoveReaderByIdAsync(Guid readerId) { - Reader maybeReader = - await this.storageBroker.SelectReaderByIdAsync(readerId); + try + { + ValidateReaderId(readerId); - ValidateStorageReader(maybeReader, readerId); + Reader maybeReader = + await this.storageBroker.SelectReaderByIdAsync(readerId); + + return await this.storageBroker.DeleteReaderAsync(maybeReader); + } + catch (InvalidReaderException invalidReaderException) + { + var readerValidationException = + new ReaderValidationException(invalidReaderException); + + this.loggingBroker.LogError(readerValidationException); - return await this.storageBroker.DeleteReaderAsync(maybeReader); + throw readerValidationException; + } } } } From e680b4f2b7520d467749cfcdbc2f9b3df458cc1d Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:33:25 +0500 Subject: [PATCH 05/13] ShouldThrowNotFoundExceptionOnRemoveReaderByIdIsNotFoundAndLogItAsync -> FAIL --- ...aderServiceTests.Validations.RemoveById.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs index 1e2d385..3433c9f 100644 --- a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Validations.RemoveById.cs @@ -55,5 +55,51 @@ await Assert.ThrowsAsync(() => this.loggingBrokerMock.VerifyNoOtherCalls(); this.storageBrokerMock.VerifyNoOtherCalls(); } + + [Fact] + public async Task ShouldThrowNotFoundExceptionOnRemoveReaderByIdIsNotFoundAndLogItAsync() + { + // given + Guid inputReaderId = Guid.NewGuid(); + Reader noReader = null; + + var notFoundReaderException = + new NotFoundReaderException(inputReaderId); + + var expectedReaderValidationException = + new ReaderValidationException(notFoundReaderException); + + this.storageBrokerMock.Setup(broker => + broker.SelectReaderByIdAsync(It.IsAny())) + .ReturnsAsync(noReader); + + // when + ValueTask removeReaderById = + this.readerService.RemoveReaderByIdAsync(inputReaderId); + + var actualReaderValidationException = + await Assert.ThrowsAsync(() => + removeReaderById.AsTask()); + + // then + actualReaderValidationException.Should() + .BeEquivalentTo(expectedReaderValidationException); + + this.storageBrokerMock.Verify(broker => + broker.SelectReaderByIdAsync(It.IsAny()), + Times.Once); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedReaderValidationException))), + Times.Once); + + this.storageBrokerMock.Verify(broker => + broker.DeleteReaderAsync(It.IsAny()), + Times.Never); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + } } } From 0a75bf1908e92f56fcb178e423e2e16bb7e6364f Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:35:16 +0500 Subject: [PATCH 06/13] ShouldThrowNotFoundExceptionOnRemoveReaderByIdIsNotFoundAndLogItAsync -> PASS --- .../Services/Foundations/Readers/ReaderService.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 555f5d0..1b11d06 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -69,6 +69,8 @@ public async ValueTask RemoveReaderByIdAsync(Guid readerId) Reader maybeReader = await this.storageBroker.SelectReaderByIdAsync(readerId); + ValidateStorageReader(maybeReader, readerId); + return await this.storageBroker.DeleteReaderAsync(maybeReader); } catch (InvalidReaderException invalidReaderException) @@ -78,6 +80,15 @@ public async ValueTask RemoveReaderByIdAsync(Guid readerId) this.loggingBroker.LogError(readerValidationException); + throw readerValidationException; + } + catch (NotFoundReaderException notFoundReaderException) + { + var readerValidationException = + new ReaderValidationException(notFoundReaderException); + + this.loggingBroker.LogError(readerValidationException); + throw readerValidationException; } } From c31f2d3f647e6a9e8ba676638527f05879e3bd55 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:38:17 +0500 Subject: [PATCH 07/13] ShouldThrowDependencyValidationOnRemoveIfDatabaseUpdateConcurrencyErrorOccursAndLogItAsync -> FAIL --- ...eaderServiceTests.Exceptions.RemoveById.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs new file mode 100644 index 0000000..1fb6782 --- /dev/null +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs @@ -0,0 +1,62 @@ +//----------------------------------------------------------- +// Copyright (c) Coalition of Good-Hearted Engineers +// Free To Use To Build Reliable Library Management Solutions +//----------------------------------------------------------- + +using FluentAssertions; +using LibraryManagement.Api.Models.Foundations.Readers; +using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; +using Microsoft.EntityFrameworkCore; +using Moq; + +namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers +{ + public partial class ReaderServiceTests + { + [Fact] + public async Task ShouldThrowDependencyValidationOnRemoveIfDatabaseUpdateConcurrencyErrorOccursAndLogItAsync() + { + // given + Guid someReaderId = Guid.NewGuid(); + var dbUpdateConcurrencyException = new DbUpdateConcurrencyException(); + + var lockedReaderException = + new LockedReaderException(dbUpdateConcurrencyException); + + var expectedReaderDependencyValidationException = + new ReaderDependencyValidationException(lockedReaderException); + + this.storageBrokerMock.Setup(broker => + broker.SelectReaderByIdAsync(It.IsAny())) + .ThrowsAsync(dbUpdateConcurrencyException); + + // when + ValueTask removeReaderById = + this.readerService.RemoveReaderByIdAsync(someReaderId); + + ReaderDependencyValidationException actualReaderDependencyValidationException = + await Assert.ThrowsAsync(() => + removeReaderById.AsTask()); + + // then + actualReaderDependencyValidationException.Should() + .BeEquivalentTo(expectedReaderDependencyValidationException); + + this.storageBrokerMock.Verify(broker => + broker.SelectReaderByIdAsync(It.IsAny()), + Times.Once); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedReaderDependencyValidationException))), + Times.Once); + + this.storageBrokerMock.Verify(broker => + broker.DeleteReaderAsync(It.IsAny()), + Times.Never); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + } + } +} From ec341b4857727b134b94c4491de0aacbbdc34d6f Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:39:33 +0500 Subject: [PATCH 08/13] ShouldThrowDependencyValidationOnRemoveIfDatabaseUpdateConcurrencyErrorOccursAndLogItAsync -> PASS --- .../Services/Foundations/Readers/ReaderService.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 1b11d06..922a616 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -7,6 +7,7 @@ using LibraryManagement.Api.Brokers.Storages; using LibraryManagement.Api.Models.Foundations.Readers; using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; +using Microsoft.EntityFrameworkCore; namespace LibraryManagement.Api.Services.Foundations.Readers { @@ -91,6 +92,18 @@ public async ValueTask RemoveReaderByIdAsync(Guid readerId) throw readerValidationException; } + catch (DbUpdateConcurrencyException dbUpdateConcurrencyException) + { + var lockedReaderException = + new LockedReaderException(dbUpdateConcurrencyException); + + var readerDependencyValidationException = + new ReaderDependencyValidationException(lockedReaderException); + + this.loggingBroker.LogError(readerDependencyValidationException); + + throw readerDependencyValidationException; + } } } } From d1ca1fcf5174968987f2a38315b535261f59f55a Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:40:46 +0500 Subject: [PATCH 09/13] ShouldThrowDependencyExceptionOnRemoveWhenSqlExceptionOccursAndLogItAsync -> FAIL --- ...eaderServiceTests.Exceptions.RemoveById.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs index 1fb6782..b649192 100644 --- a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs @@ -6,6 +6,7 @@ using FluentAssertions; using LibraryManagement.Api.Models.Foundations.Readers; using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Moq; @@ -58,5 +59,47 @@ await Assert.ThrowsAsync(() => this.storageBrokerMock.VerifyNoOtherCalls(); this.loggingBrokerMock.VerifyNoOtherCalls(); } + + [Fact] + public async Task ShouldThrowDependencyExceptionOnRemoveWhenSqlExceptionOccursAndLogItAsync() + { + // given + Guid someLocationId = Guid.NewGuid(); + SqlException sqlException = GetSqlError(); + + var failedReaderStorageException = + new FailedReaderStorageException(sqlException); + + var expectedReaderDependencyException = + new ReaderDependencyException(failedReaderStorageException); + + this.storageBrokerMock.Setup(broker => + broker.SelectReaderByIdAsync(It.IsAny())) + .ThrowsAsync(sqlException); + + // when + ValueTask deleteReaderTask = + this.readerService.RemoveReaderByIdAsync(someLocationId); + + ReaderDependencyException actualReaderDependencyException = + await Assert.ThrowsAsync(() => + deleteReaderTask.AsTask()); + + // then + actualReaderDependencyException.Should() + .BeEquivalentTo(expectedReaderDependencyException); + + this.storageBrokerMock.Verify(broker => + broker.SelectReaderByIdAsync(It.IsAny()), + Times.Once); + + this.loggingBrokerMock.Verify(broker => + broker.LogCritical(It.Is(SameExceptionAs( + expectedReaderDependencyException))), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + } } } From a509558998a3221f4be67c5b6282cdab33059ce6 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:42:07 +0500 Subject: [PATCH 10/13] ShouldThrowDependencyExceptionOnRemoveWhenSqlExceptionOccursAndLogItAsync -> PASS --- .../Services/Foundations/Readers/ReaderService.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 922a616..4aab63f 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -7,6 +7,7 @@ using LibraryManagement.Api.Brokers.Storages; using LibraryManagement.Api.Models.Foundations.Readers; using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; namespace LibraryManagement.Api.Services.Foundations.Readers @@ -104,6 +105,18 @@ public async ValueTask RemoveReaderByIdAsync(Guid readerId) throw readerDependencyValidationException; } + catch (SqlException sqlException) + { + var failedReaderStorageException = + new FailedReaderStorageException(sqlException); + + var readerDependencyException = + new ReaderDependencyException(failedReaderStorageException); + + this.loggingBroker.LogCritical(readerDependencyException); + + throw readerDependencyException; + } } } } From bd5844237b418658232c08caba80d5f99b641e72 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:43:34 +0500 Subject: [PATCH 11/13] ShouldThrowServiceExceptionOnRemoveIfExceptionOccursAndLogItAsync -> FAIL --- ...eaderServiceTests.Exceptions.RemoveById.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs index b649192..c1cae50 100644 --- a/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs +++ b/LibraryManagement.Api.Tests.Unit/Services/Foundations/Readers/ReaderServiceTests.Exceptions.RemoveById.cs @@ -101,5 +101,47 @@ await Assert.ThrowsAsync(() => this.storageBrokerMock.VerifyNoOtherCalls(); this.loggingBrokerMock.VerifyNoOtherCalls(); } + + [Fact] + public async Task ShouldThrowServiceExceptionOnRemoveIfExceptionOccursAndLogItAsync() + { + // given + Guid someReaderId = Guid.NewGuid(); + var serviceException = new Exception(); + + var failedReaderServiceException = + new FailedReaderServiceException(serviceException); + + var expectedReaderServiceException = + new ReaderServiceException(failedReaderServiceException); + + this.storageBrokerMock.Setup(broker => + broker.SelectReaderByIdAsync(It.IsAny())) + .ThrowsAsync(serviceException); + + // when + ValueTask removeReaderByIdTask = + this.readerService.RemoveReaderByIdAsync(someReaderId); + + ReaderServiceException actualReaderServiceException = + await Assert.ThrowsAsync(() => + removeReaderByIdTask.AsTask()); + + // then + actualReaderServiceException.Should() + .BeEquivalentTo(expectedReaderServiceException); + + this.storageBrokerMock.Verify(broker => + broker.SelectReaderByIdAsync(It.IsAny()), + Times.Once); + + this.loggingBrokerMock.Verify(broker => + broker.LogError(It.Is(SameExceptionAs( + expectedReaderServiceException))), + Times.Once); + + this.storageBrokerMock.VerifyNoOtherCalls(); + this.loggingBrokerMock.VerifyNoOtherCalls(); + } } } From d67223dd33522f2dfe482e02df33d8421c99dc23 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:44:55 +0500 Subject: [PATCH 12/13] ShouldThrowServiceExceptionOnRemoveIfExceptionOccursAndLogItAsync -> PASS --- .../Services/Foundations/Readers/ReaderService.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index 4aab63f..c9e8502 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -117,6 +117,18 @@ public async ValueTask RemoveReaderByIdAsync(Guid readerId) throw readerDependencyException; } + catch (Exception exception) + { + var failedReaderServiceException = + new FailedReaderServiceException(exception); + + var readerServiceException = + new ReaderServiceException(failedReaderServiceException); + + this.loggingBroker.LogError(readerServiceException); + + throw readerServiceException; + } } } } From d71e9d449e15e32062b1bbf235de4a2b6c4315c0 Mon Sep 17 00:00:00 2001 From: DilmurodDeveloper Date: Mon, 21 Jul 2025 18:46:03 +0500 Subject: [PATCH 13/13] CODE RUB: Implement TryCatch --- .../Foundations/Readers/ReaderService.cs | 75 ++----------------- 1 file changed, 8 insertions(+), 67 deletions(-) diff --git a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs index c9e8502..a20251b 100644 --- a/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs +++ b/LibraryManagement.Api/Services/Foundations/Readers/ReaderService.cs @@ -6,9 +6,6 @@ using LibraryManagement.Api.Brokers.Loggings; using LibraryManagement.Api.Brokers.Storages; using LibraryManagement.Api.Models.Foundations.Readers; -using LibraryManagement.Api.Models.Foundations.Readers.Exceptions; -using Microsoft.Data.SqlClient; -using Microsoft.EntityFrameworkCore; namespace LibraryManagement.Api.Services.Foundations.Readers { @@ -62,73 +59,17 @@ public ValueTask ModifyReaderAsync(Reader reader) => return await this.storageBroker.UpdateReaderAsync(reader); }); - public async ValueTask RemoveReaderByIdAsync(Guid readerId) + public ValueTask RemoveReaderByIdAsync(Guid readerId) => + TryCatch(async () => { - try - { - ValidateReaderId(readerId); - - Reader maybeReader = - await this.storageBroker.SelectReaderByIdAsync(readerId); - - ValidateStorageReader(maybeReader, readerId); - - return await this.storageBroker.DeleteReaderAsync(maybeReader); - } - catch (InvalidReaderException invalidReaderException) - { - var readerValidationException = - new ReaderValidationException(invalidReaderException); - - this.loggingBroker.LogError(readerValidationException); - - throw readerValidationException; - } - catch (NotFoundReaderException notFoundReaderException) - { - var readerValidationException = - new ReaderValidationException(notFoundReaderException); - - this.loggingBroker.LogError(readerValidationException); - - throw readerValidationException; - } - catch (DbUpdateConcurrencyException dbUpdateConcurrencyException) - { - var lockedReaderException = - new LockedReaderException(dbUpdateConcurrencyException); - - var readerDependencyValidationException = - new ReaderDependencyValidationException(lockedReaderException); - - this.loggingBroker.LogError(readerDependencyValidationException); - - throw readerDependencyValidationException; - } - catch (SqlException sqlException) - { - var failedReaderStorageException = - new FailedReaderStorageException(sqlException); - - var readerDependencyException = - new ReaderDependencyException(failedReaderStorageException); - - this.loggingBroker.LogCritical(readerDependencyException); - - throw readerDependencyException; - } - catch (Exception exception) - { - var failedReaderServiceException = - new FailedReaderServiceException(exception); + ValidateReaderId(readerId); - var readerServiceException = - new ReaderServiceException(failedReaderServiceException); + Reader maybeReader = + await this.storageBroker.SelectReaderByIdAsync(readerId); - this.loggingBroker.LogError(readerServiceException); + ValidateStorageReader(maybeReader, readerId); - throw readerServiceException; - } - } + return await this.storageBroker.DeleteReaderAsync(maybeReader); + }); } }