Skip to content

Commit 6fd4621

Browse files
Merge pull request #48 from DilmurodDeveloper/users/DilmurodDeveloper/foundations-reader-add
FOUNDATIONS: Add Reader
2 parents 7a98bb7 + 5e87a7f commit 6fd4621

17 files changed

+691
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using EFxceptions.Models.Exceptions;
7+
using LibraryManagement.Api.Models.Foundations.Readers;
8+
using LibraryManagement.Api.Models.Foundations.Readers.Exceptions;
9+
using Microsoft.Data.SqlClient;
10+
using Moq;
11+
12+
namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers
13+
{
14+
public partial class ReaderServiceTests
15+
{
16+
[Fact]
17+
public async Task ShouldThrowCriticalDependencyExceptionOnAddIfSqlErrorOccursAndLogItAsync()
18+
{
19+
// given
20+
Reader someReader = CreateRandomReader();
21+
SqlException sqlException = GetSqlError();
22+
23+
var failedReaderStorageException =
24+
new FailedReaderStorageException(sqlException);
25+
26+
var expectedReaderDependencyException =
27+
new ReaderDependencyException(failedReaderStorageException);
28+
29+
this.storageBrokerMock.Setup(broker =>
30+
broker.InsertReaderAsync(someReader))
31+
.ThrowsAsync(sqlException);
32+
33+
// when
34+
ValueTask<Reader> addReaderTask =
35+
this.readerService.AddReaderAsync(someReader);
36+
37+
// then
38+
await Assert.ThrowsAsync<ReaderDependencyException>(() =>
39+
addReaderTask.AsTask());
40+
41+
this.storageBrokerMock.Verify(broker =>
42+
broker.InsertReaderAsync(someReader),
43+
Times.Once);
44+
45+
this.loggingBrokerMock.Verify(broker =>
46+
broker.LogCritical(It.Is(SameExceptionAs(
47+
expectedReaderDependencyException))),
48+
Times.Once);
49+
50+
this.storageBrokerMock.VerifyNoOtherCalls();
51+
this.loggingBrokerMock.VerifyNoOtherCalls();
52+
}
53+
54+
[Fact]
55+
public async Task ShouldThrowDependencyValidationOnAddIfDuplicateKeyErrorOccursAndLogItAsync()
56+
{
57+
// given
58+
Reader someReader = CreateRandomReader();
59+
string someMessage = GetRandomString();
60+
61+
var duplicateKeyException =
62+
new DuplicateKeyException(someMessage);
63+
64+
var alreadyExistsReaderException =
65+
new AlreadyExistsReaderException(duplicateKeyException);
66+
67+
var expectedReaderDependencyValidationException =
68+
new ReaderDependencyValidationException(alreadyExistsReaderException);
69+
70+
this.storageBrokerMock.Setup(broker =>
71+
broker.InsertReaderAsync(someReader))
72+
.ThrowsAsync(duplicateKeyException);
73+
74+
// when
75+
ValueTask<Reader> addReaderTask =
76+
this.readerService.AddReaderAsync(someReader);
77+
78+
// then
79+
await Assert.ThrowsAsync<ReaderDependencyValidationException>(() =>
80+
addReaderTask.AsTask());
81+
82+
this.storageBrokerMock.Verify(broker =>
83+
broker.InsertReaderAsync(someReader),
84+
Times.Once);
85+
86+
this.loggingBrokerMock.Verify(broker =>
87+
broker.LogError(It.Is(SameExceptionAs(
88+
expectedReaderDependencyValidationException))),
89+
Times.Once);
90+
91+
this.storageBrokerMock.VerifyNoOtherCalls();
92+
this.loggingBrokerMock.VerifyNoOtherCalls();
93+
}
94+
95+
[Fact]
96+
public async Task ShouldThrowServiceExceptionOnAddIfServiceErrorOccursAndLogItAsync()
97+
{
98+
// given
99+
Reader someReader = CreateRandomReader();
100+
var serviceException = new Exception();
101+
102+
var failedReaderServiceException =
103+
new FailedReaderServiceException(serviceException);
104+
105+
var expectedReaderServiceException =
106+
new ReaderServiceException(failedReaderServiceException);
107+
108+
this.storageBrokerMock.Setup(broker =>
109+
broker.InsertReaderAsync(someReader))
110+
.ThrowsAsync(serviceException);
111+
112+
// when
113+
ValueTask<Reader> addReaderTask =
114+
this.readerService.AddReaderAsync(someReader);
115+
116+
// then
117+
await Assert.ThrowsAsync<ReaderServiceException>(() =>
118+
addReaderTask.AsTask());
119+
120+
this.storageBrokerMock.Verify(broker =>
121+
broker.InsertReaderAsync(someReader),
122+
Times.Once);
123+
124+
this.loggingBrokerMock.Verify(broker =>
125+
broker.LogError(It.Is(SameExceptionAs(
126+
expectedReaderServiceException))),
127+
Times.Once);
128+
129+
this.storageBrokerMock.VerifyNoOtherCalls();
130+
this.loggingBrokerMock.VerifyNoOtherCalls();
131+
}
132+
}
133+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using FluentAssertions;
7+
using Force.DeepCloner;
8+
using LibraryManagement.Api.Models.Foundations.Readers;
9+
using Moq;
10+
11+
namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers
12+
{
13+
public partial class ReaderServiceTests
14+
{
15+
[Fact]
16+
public async Task ShouldAddReaderAsync()
17+
{
18+
// given
19+
Reader randomReader = CreateRandomReader();
20+
Reader inputReader = randomReader;
21+
Reader storageReader = inputReader;
22+
Reader expectedReader = storageReader.DeepClone();
23+
24+
this.storageBrokerMock.Setup(broker =>
25+
broker.InsertReaderAsync(inputReader))
26+
.ReturnsAsync(storageReader);
27+
28+
// when
29+
Reader actualReader =
30+
await this.readerService.AddReaderAsync(inputReader);
31+
32+
// then
33+
actualReader.Should().BeEquivalentTo(expectedReader);
34+
35+
this.storageBrokerMock.Verify(broker =>
36+
broker.InsertReaderAsync(inputReader),
37+
Times.Once);
38+
39+
this.storageBrokerMock.VerifyNoOtherCalls();
40+
this.loggingBrokerMock.VerifyNoOtherCalls();
41+
}
42+
}
43+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using LibraryManagement.Api.Models.Foundations.Readers;
7+
using LibraryManagement.Api.Models.Foundations.Readers.Exceptions;
8+
using Moq;
9+
10+
namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers
11+
{
12+
public partial class ReaderServiceTests
13+
{
14+
[Fact]
15+
public async Task ShouldThrowValidationExceptionOnAddIfReaderIsNullAndLogItAsync()
16+
{
17+
// given
18+
Reader nullReader = null;
19+
var nullReaderException = new NullReaderException();
20+
21+
var expectedReaderValidationException =
22+
new ReaderValidationException(nullReaderException);
23+
24+
// when
25+
ValueTask<Reader> addReaderTask =
26+
this.readerService.AddReaderAsync(nullReader);
27+
28+
// then
29+
await Assert.ThrowsAsync<ReaderValidationException>(() =>
30+
addReaderTask.AsTask());
31+
32+
this.loggingBrokerMock.Verify(broker =>
33+
broker.LogError(It.Is(SameExceptionAs(
34+
expectedReaderValidationException))),
35+
Times.Once);
36+
37+
this.storageBrokerMock.Verify(broker =>
38+
broker.InsertReaderAsync(It.IsAny<Reader>()),
39+
Times.Never);
40+
41+
this.loggingBrokerMock.VerifyNoOtherCalls();
42+
this.storageBrokerMock.VerifyNoOtherCalls();
43+
}
44+
45+
[Theory]
46+
[InlineData(null)]
47+
[InlineData("")]
48+
[InlineData(" ")]
49+
public async Task ShouldThrowValidationExceptionOnAddIfReaderIsInvalidAndLogItAsync(
50+
string invalidText)
51+
{
52+
// given
53+
var invalidReader = new Reader
54+
{
55+
FirstName = invalidText
56+
};
57+
58+
var invalidReaderException = new InvalidReaderException();
59+
60+
invalidReaderException.AddData(
61+
key: nameof(Reader.ReaderId),
62+
values: "Id is required");
63+
64+
invalidReaderException.AddData(
65+
key: nameof(Reader.FirstName),
66+
values: "Text is required");
67+
68+
invalidReaderException.AddData(
69+
key: nameof(Reader.LastName),
70+
values: "Text is required");
71+
72+
invalidReaderException.AddData(
73+
key: nameof(Reader.DateOfBirth),
74+
values: "Date is required");
75+
76+
var expectedReaderValidationException =
77+
new ReaderValidationException(invalidReaderException);
78+
79+
// when
80+
ValueTask<Reader> addReaderTask =
81+
this.readerService.AddReaderAsync(invalidReader);
82+
83+
// then
84+
await Assert.ThrowsAsync<ReaderValidationException>(() =>
85+
addReaderTask.AsTask());
86+
87+
this.loggingBrokerMock.Verify(broker =>
88+
broker.LogError(It.Is(SameExceptionAs(
89+
expectedReaderValidationException))),
90+
Times.Once);
91+
92+
this.storageBrokerMock.Verify(broker =>
93+
broker.InsertReaderAsync(It.IsAny<Reader>()),
94+
Times.Never);
95+
96+
this.loggingBrokerMock.VerifyNoOtherCalls();
97+
this.storageBrokerMock.VerifyNoOtherCalls();
98+
}
99+
}
100+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using System.Linq.Expressions;
7+
using System.Runtime.CompilerServices;
8+
using LibraryManagement.Api.Brokers.Loggings;
9+
using LibraryManagement.Api.Brokers.Storages;
10+
using LibraryManagement.Api.Models.Foundations.Readers;
11+
using LibraryManagement.Api.Services.Foundations.Readers;
12+
using Microsoft.Data.SqlClient;
13+
using Moq;
14+
using Tynamix.ObjectFiller;
15+
using Xeptions;
16+
17+
namespace LibraryManagement.Api.Tests.Unit.Services.Foundations.Readers
18+
{
19+
public partial class ReaderServiceTests
20+
{
21+
private readonly Mock<IStorageBroker> storageBrokerMock;
22+
private readonly Mock<ILoggingBroker> loggingBrokerMock;
23+
private readonly IReaderService readerService;
24+
25+
public ReaderServiceTests()
26+
{
27+
this.storageBrokerMock = new Mock<IStorageBroker>();
28+
this.loggingBrokerMock = new Mock<ILoggingBroker>();
29+
this.readerService = new ReaderService(
30+
storageBroker: this.storageBrokerMock.Object,
31+
loggingBroker: this.loggingBrokerMock.Object);
32+
}
33+
34+
private static Reader CreateRandomReader() =>
35+
CreateReaderFiller(date: GetRandomDateTimeOffset()).Create();
36+
37+
private static DateTimeOffset GetRandomDateTimeOffset() =>
38+
new DateTimeRange(earliestDate: new DateTime()).GetValue();
39+
40+
private static SqlException GetSqlError() =>
41+
(SqlException)RuntimeHelpers.GetUninitializedObject(typeof(SqlException));
42+
43+
private static string GetRandomString() =>
44+
new MnemonicString().GetValue();
45+
46+
private Expression<Func<Xeption, bool>> SameExceptionAs(Xeption expectedException) =>
47+
actualException => actualException.SameExceptionAs(expectedException);
48+
49+
private static Filler<Reader> CreateReaderFiller(DateTimeOffset date)
50+
{
51+
var filler = new Filler<Reader>();
52+
53+
filler.Setup()
54+
.OnType<DateTimeOffset>().Use(date);
55+
56+
return filler;
57+
}
58+
}
59+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using Xeptions;
7+
8+
namespace LibraryManagement.Api.Models.Foundations.Readers.Exceptions
9+
{
10+
public class AlreadyExistsReaderException : Xeption
11+
{
12+
public AlreadyExistsReaderException(Exception innerException)
13+
: base(message: "Reader already exists.", innerException)
14+
{ }
15+
}
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using Xeptions;
7+
8+
namespace LibraryManagement.Api.Models.Foundations.Readers.Exceptions
9+
{
10+
public class FailedReaderServiceException : Xeption
11+
{
12+
public FailedReaderServiceException(Exception innerException)
13+
: base(message: "Failed reader service error occurred, contact support.",
14+
innerException)
15+
{ }
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//-----------------------------------------------------------
2+
// Copyright (c) Coalition of Good-Hearted Engineers
3+
// Free To Use To Build Reliable Library Management Solutions
4+
//-----------------------------------------------------------
5+
6+
using Xeptions;
7+
8+
namespace LibraryManagement.Api.Models.Foundations.Readers.Exceptions
9+
{
10+
public class FailedReaderStorageException : Xeption
11+
{
12+
public FailedReaderStorageException(Exception innerException)
13+
: base(message: "Failed reader storage error occurred, contact support.",
14+
innerException)
15+
{ }
16+
}
17+
}

0 commit comments

Comments
 (0)