From cd609d3038253bbb232ac6581f70fa4d3749b0b4 Mon Sep 17 00:00:00 2001 From: "Jefferson L. da Silva" Date: Thu, 18 Dec 2025 18:23:01 -0300 Subject: [PATCH 1/5] Updates .NET packages to latest versions Updates .NET packages to their latest versions, including essential libraries and testing dependencies. This ensures the project benefits from the newest features, security patches, and performance improvements. Includes updates to bulk extensions library. Adds global.json to define the .NET SDK version, also adds bogus package to mock data for unit tests and improve testing data generation. Removes `MaxCpuCount` setting from `CodeCoverage.runsettings`. --- CodeCoverage.runsettings | 3 - Directory.Packages.props | 59 ++-- .../Endpoints/InvoiceEndpointsTests.cs | 145 +++------ .../Endpoints/JobScheduleEndPointsTests.cs | 110 ++----- .../InvoiceReminder.API.UnitTests.csproj | 1 + .../Endpoints/GoogleOAuthEndpoints.cs | 16 +- .../Endpoints/InvoiceEndpoints.cs | 28 +- .../Endpoints/JobScheduleEndpoints.cs | 37 ++- .../Endpoints/LoginEndpoints.cs | 11 +- .../Endpoints/ScanEmailDefinitionEndpoints.cs | 35 +- .../Endpoints/SendMessageEndpoints.cs | 11 +- .../Endpoints/UserEndpoints.cs | 44 ++- .../Exceptions/GlobalExceptionHandler.cs | 5 +- .../AppServices/BaseAppServiceTests.cs | 40 +-- .../EmailAuthTokenAppServiceTests.cs | 36 ++- .../AppServices/InvoiceAppServiceTests.cs | 41 ++- .../AppServices/JobScheduleAppServiceTests.cs | 64 ++-- .../ScanEmailDefinitionAppServiceTests.cs | 90 +++--- .../AppServices/UserAppServiceTests.cs | 33 +- ...voiceReminder.Application.UnitTests.csproj | 1 + .../InvoiceReminder.Data.csproj | 3 +- .../Repository/BaseRepository.cs | 3 +- .../Extensions/EntityExtensionsTests.cs | 79 ++--- .../Extensions/UserExtensionsTests.cs | 302 ++++++++---------- ...ceReminder.DomainEntities.UnitTests.csproj | 1 + .../Data/Repository/BaseRepositoryTests.cs | 52 +-- .../ScanEmailDefinitionRepositoryTests.cs | 48 ++- .../Data/Repository/UserRepositoryTests.cs | 29 +- ...ceReminder.Infrastructure.UnitTests.csproj | 1 + .../HostedService/QuartzHostedServiceTests.cs | 57 +++- ...oiceReminder.JobScheduler.UnitTests.csproj | 1 + InvoiceReminder.sln | 1 + global.json | 9 + 33 files changed, 779 insertions(+), 617 deletions(-) create mode 100644 global.json diff --git a/CodeCoverage.runsettings b/CodeCoverage.runsettings index 2e8682f..bfcbd04 100644 --- a/CodeCoverage.runsettings +++ b/CodeCoverage.runsettings @@ -1,8 +1,5 @@ - - 1 - diff --git a/Directory.Packages.props b/Directory.Packages.props index 31eb18a..4b525de 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,56 +3,61 @@ true true + + + + + + + + + + + + + + + + + + + + + + + - + + + - - - - - - - - - - - - - - - - - - - - - + - + - - + - + + - + diff --git a/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs b/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs index 505d4ed..a42133d 100644 --- a/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs +++ b/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.API.UnitTests.Factories; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Application.ViewModels; @@ -22,6 +23,8 @@ public sealed class InvoiceEndpointsTests private readonly HttpClient _client; private readonly IAuthorizationService _authorizationService; private readonly IInvoiceAppService _invoiceAppService; + private readonly Faker _invoiceViewModelFaker; + private readonly Faker _faker; private const string basepath = "/api/invoice"; public TestContext TestContext { get; set; } @@ -34,6 +37,26 @@ public InvoiceEndpointsTests() _client = factory.CreateClient(); _authorizationService = serviceProvider.GetRequiredService(); _invoiceAppService = serviceProvider.GetRequiredService(); + _faker = new Faker(); + + _invoiceViewModelFaker = new Faker() + .RuleFor(i => i.Id, faker => faker.Random.Guid()) + .RuleFor(i => i.UserId, faker => faker.Random.Guid()) + .RuleFor(i => i.Bank, faker => faker.PickRandom( + "Banco do Brasil", + "Bradesco", + "Itaú", + "Caixa Econômica Federal", + "Santander", + "Safra", + "Citibank", + "BTG Pactual")) + .RuleFor(i => i.Beneficiary, faker => faker.Person.FullName) + .RuleFor(i => i.Amount, faker => faker.Finance.Amount(10, 10000)) + .RuleFor(i => i.Barcode, faker => faker.Random.AlphaNumeric(44)) + .RuleFor(i => i.DueDate, faker => faker.Date.Future().ToUniversalTime()) + .RuleFor(i => i.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(i => i.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } #region MapGet Tests @@ -44,29 +67,8 @@ public async Task GetAllInvoices_WhenUserIsAuthenticated_ShouldReturnOk() var request = new HttpRequestMessage(HttpMethod.Get, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var expectedResult = Result>.Success( - [ - new() { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }, - new() { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "José da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - } - ]); + var invoices = _invoiceViewModelFaker.Generate(2); + var expectedResult = Result>.Success(invoices); _ = _invoiceAppService.GetAll().Returns(expectedResult); @@ -140,17 +142,7 @@ public async Task GetInvoiceById_WhenUserIsAuthenticated_ShouldReturnOk() request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); var expectedResult = Result.Success( - new() - { - Id = id, - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }); + _invoiceViewModelFaker.RuleFor(i => i.Id, id).Generate()); _ = _invoiceAppService.GetByIdAsync(Arg.Any(), Arg.Any()).Returns(expectedResult); @@ -274,21 +266,12 @@ public async Task GetInvoiceById_WhenUserIsAuthenticatedButNotExists_ShouldRetur public async Task GetInvoiceByBarcode_WhenUserIsAuthenticated_ShouldReturnOk() { // Arrange - var value = "12345678901234567890123456789012345678901234"; - var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{value}"); + var barcode = _faker.Random.AlphaNumeric(44); + var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{barcode}"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var expectedResult = Result.Success(new() - { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }); + var expectedResult = Result.Success( + _invoiceViewModelFaker.RuleFor(i => i.Barcode, barcode).Generate()); _ = _invoiceAppService.GetByBarcodeAsync(Arg.Any(), Arg.Any()) .Returns(expectedResult); @@ -313,8 +296,8 @@ public async Task GetInvoiceByBarcode_WhenUserIsAuthenticated_ShouldReturnOk() public async Task GetInvoiceByBarcode_WhenUserIsNotAuthenticated_ShouldReturnUnauthorized() { // Arrange - var value = "12345678901234567890123456789012345678901234"; - var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{value}"); + var barcode = _faker.Random.AlphaNumeric(44); + var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{barcode}"); _ = _authorizationService.AuthorizeAsync(Arg.Any(), Arg.Any(), Arg.Any>()) @@ -331,8 +314,8 @@ public async Task GetInvoiceByBarcode_WhenUserIsNotAuthenticated_ShouldReturnUna public async Task GetInvoiceByBarcode_WhenUserIsAuthenticatedButServiceFails_ShouldReturnBadRequest() { // Arrange - var value = "12345678901234567890123456789012345678901234"; - var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{value}"); + var barcode = _faker.Random.AlphaNumeric(44); + var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{barcode}"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); _ = _invoiceAppService.GetByBarcodeAsync(Arg.Any(), Arg.Any()) @@ -358,8 +341,8 @@ public async Task GetInvoiceByBarcode_WhenUserIsAuthenticatedButServiceFails_Sho public async Task GetInvoiceByBarcode_WhenUserIsAuthenticatedButServiceFails_ShouldReturnInternalServerError() { // Arrange - var value = "12345678901234567890123456789012345678901234"; - var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{value}"); + var barcode = _faker.Random.AlphaNumeric(44); + var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{barcode}"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); _ = _invoiceAppService.GetByBarcodeAsync(Arg.Any(), Arg.Any()) @@ -385,8 +368,8 @@ public async Task GetInvoiceByBarcode_WhenUserIsAuthenticatedButServiceFails_Sho public async Task GetInvoiceByBarcode_WhenUserIsAuthenticatedButNotExists_ShouldReturnNotFound() { // Arrange - var value = "12345678901234567890123456789012345678901234"; - var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{value}"); + var barcode = _faker.Random.AlphaNumeric(44); + var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-barcode/{barcode}"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); var expectedResult = Result.Failure($"Invoice not Found."); @@ -421,18 +404,7 @@ public async Task CreateInvoice_WhenUserIsAuthenticated_ShouldReturnCreated() var request = new HttpRequestMessage(HttpMethod.Post, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var invoiceViewModel = new InvoiceViewModel - { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var invoiceViewModel = _invoiceViewModelFaker.Generate(); var expectedResult = Result.Success(invoiceViewModel); _ = _invoiceAppService.AddAsync(Arg.Any(), Arg.Any()) @@ -479,18 +451,7 @@ public async Task CreateInvoice_WhenUserIsAuthenticatedButServiceFails_ShouldRet var request = new HttpRequestMessage(HttpMethod.Post, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var invoiceViewModel = new InvoiceViewModel - { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var invoiceViewModel = _invoiceViewModelFaker.Generate(); var expectedResult = Result.Failure("Service error"); _ = _invoiceAppService.AddAsync(Arg.Any(), Arg.Any()) @@ -524,18 +485,7 @@ public async Task UpdateInvoice_WhenUserIsAuthenticated_ShouldReturnOk() var request = new HttpRequestMessage(HttpMethod.Put, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var invoiceViewModel = new InvoiceViewModel - { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var invoiceViewModel = _invoiceViewModelFaker.Generate(); var expectedResult = Result.Success(invoiceViewModel); _ = _invoiceAppService.UpdateAsync(Arg.Any(), Arg.Any()) @@ -582,18 +532,7 @@ public async Task UpdateInvoice_WhenUserIsAuthenticatedButServiceFails_ShouldRet var request = new HttpRequestMessage(HttpMethod.Put, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var invoiceViewModel = new InvoiceViewModel - { - Id = Guid.NewGuid(), - Bank = "Banco do Brasil", - Beneficiary = "João da Silva", - Amount = 100.00m, - Barcode = "12345678901234567890123456789012345678901234", - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var invoiceViewModel = _invoiceViewModelFaker.Generate(); var expectedResult = Result.Failure("Service error"); _ = _invoiceAppService.UpdateAsync(Arg.Any(), Arg.Any()) diff --git a/InvoiceReminder.API.UnitTests/Endpoints/JobScheduleEndPointsTests.cs b/InvoiceReminder.API.UnitTests/Endpoints/JobScheduleEndPointsTests.cs index 172d862..ee2d111 100644 --- a/InvoiceReminder.API.UnitTests/Endpoints/JobScheduleEndPointsTests.cs +++ b/InvoiceReminder.API.UnitTests/Endpoints/JobScheduleEndPointsTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.API.UnitTests.Factories; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Application.ViewModels; @@ -22,6 +23,7 @@ public sealed class JobScheduleEndPointsTests private readonly HttpClient _client; private readonly IAuthorizationService _authorizationService; private readonly IJobScheduleAppService _jobScheduleAppService; + private readonly Faker _jobScheduleViewModelFaker; private const string basepath = "/api/job_schedule"; public TestContext TestContext { get; set; } @@ -34,6 +36,20 @@ public JobScheduleEndPointsTests() _client = factory.CreateClient(); _authorizationService = serviceProvider.GetRequiredService(); _jobScheduleAppService = serviceProvider.GetRequiredService(); + + _jobScheduleViewModelFaker = new Faker() + .RuleFor(j => j.Id, faker => faker.Random.Guid()) + .RuleFor(j => j.UserId, faker => faker.Random.Guid()) + .RuleFor(j => j.CronExpression, faker => faker.PickRandom( + "0 0/5 * * * ?", // Every 5 minutes + "0 0 * * * ?", // Every hour + "0 0 0 * * ?", // Every day at midnight + "0 0 0 ? * MON", // Every Monday + "0 0 0 1 * ?", // First day of month + "0 0 0 1 1 ?", // Every January 1st + "0 0 12 * * ?")) // Every noon + .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } #region MapGet Tests @@ -44,23 +60,8 @@ public async Task GetAllJobSchedules_WhenUserIsAuthenticated_ShouldReturnOk() var request = new HttpRequestMessage(HttpMethod.Get, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var expectedResult = Result>.Success( - [ - new() { - Id = Guid.NewGuid(), - UserId = Guid.NewGuid(), - CronExpression = "0 0 * * *", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }, - new() { - Id = Guid.NewGuid(), - UserId = Guid.NewGuid(), - CronExpression = "0 0 * 1 1", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - } - ]); + var jobSchedules = _jobScheduleViewModelFaker.Generate(2); + var expectedResult = Result>.Success(jobSchedules); _ = _jobScheduleAppService.GetAll().Returns(expectedResult); @@ -134,14 +135,7 @@ public async Task GetJobScheduleById_WhenUserIsAuthenticated_ShouldReturnOk() request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); var expectedResult = Result.Success( - new() - { - Id = id, - UserId = Guid.NewGuid(), - CronExpression = "0 0 * 1 2", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }); + _jobScheduleViewModelFaker.RuleFor(j => j.Id, id).Generate()); _ = _jobScheduleAppService.GetByIdAsync(Arg.Any(), Arg.Any()).Returns(expectedResult); @@ -269,23 +263,11 @@ public async Task GetJobScheduleByUserId_WhenUserIsAuthenticated_ShouldReturnOk( var request = new HttpRequestMessage(HttpMethod.Get, $"{basepath}/getby-userid/{id}"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var expectedResult = Result>.Success( - [ - new() { - Id = Guid.NewGuid(), - UserId = id, - CronExpression = "0 0 * * *", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }, - new() { - Id = Guid.NewGuid(), - UserId = id, - CronExpression = "0 0 * 1 1", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - } - ]); + var jobSchedules = _jobScheduleViewModelFaker + .RuleFor(j => j.UserId, id) + .Generate(2); + + var expectedResult = Result>.Success(jobSchedules); _ = _jobScheduleAppService.GetByUserIdAsync(Arg.Any(), Arg.Any()) .Returns(expectedResult); @@ -417,15 +399,7 @@ public async Task CreateJobSchedule_WhenUserIsAuthenticated_ShouldReturnCreated( var request = new HttpRequestMessage(HttpMethod.Post, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var jobScheduleViewModel = new JobScheduleViewModel - { - Id = Guid.NewGuid(), - UserId = Guid.NewGuid(), - CronExpression = "0 0 * * *", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var jobScheduleViewModel = _jobScheduleViewModelFaker.Generate(); var expectedResult = Result.Success(jobScheduleViewModel); _ = _jobScheduleAppService.AddNewJobAsync(Arg.Any(), Arg.Any()) @@ -472,15 +446,7 @@ public async Task CreateJobSchedule_WhenUserIsAuthenticatedButServiceFails_Shoul var request = new HttpRequestMessage(HttpMethod.Post, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var jobScheduleViewModel = new JobScheduleViewModel - { - Id = Guid.NewGuid(), - UserId = Guid.NewGuid(), - CronExpression = "0 0 * * *", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var jobScheduleViewModel = _jobScheduleViewModelFaker.Generate(); var expectedResult = Result.Failure("Service error"); _ = _jobScheduleAppService.AddNewJobAsync(Arg.Any(), Arg.Any()) @@ -515,15 +481,7 @@ public async Task UpdateJobSchedule_WhenUserIsAuthenticated_ShouldReturnOk() var request = new HttpRequestMessage(HttpMethod.Put, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var jobScheduleViewModel = new JobScheduleViewModel - { - Id = id, - UserId = Guid.NewGuid(), - CronExpression = "0 0 * * *", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var jobScheduleViewModel = _jobScheduleViewModelFaker.RuleFor(j => j.Id, id).Generate(); var expectedResult = Result.Success(jobScheduleViewModel); _ = _jobScheduleAppService.UpdateAsync(Arg.Any(), Arg.Any()) @@ -571,15 +529,7 @@ public async Task UpdateJobSchedule_WhenUserIsAuthenticatedButServiceFails_Shoul var request = new HttpRequestMessage(HttpMethod.Put, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - var jobScheduleViewModel = new JobScheduleViewModel - { - Id = id, - UserId = Guid.NewGuid(), - CronExpression = "0 0 * * *", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - + var jobScheduleViewModel = _jobScheduleViewModelFaker.RuleFor(j => j.Id, id).Generate(); var expectedResult = Result.Failure("Service error"); _ = _jobScheduleAppService.UpdateAsync(Arg.Any(), Arg.Any()) @@ -612,7 +562,9 @@ public async Task DeleteJobSchedule_WhenUserIsAuthenticated_ShouldReturnNoConten // Arrange var request = new HttpRequestMessage(HttpMethod.Delete, basepath); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); - request.Content = JsonContent.Create(new JobScheduleViewModel { Id = Guid.NewGuid() }); + + var jobScheduleViewModel = _jobScheduleViewModelFaker.Generate(); + request.Content = JsonContent.Create(jobScheduleViewModel); var expectedResult = Result.Success(null); diff --git a/InvoiceReminder.API.UnitTests/InvoiceReminder.API.UnitTests.csproj b/InvoiceReminder.API.UnitTests/InvoiceReminder.API.UnitTests.csproj index cf1117e..46c3e67 100644 --- a/InvoiceReminder.API.UnitTests/InvoiceReminder.API.UnitTests.csproj +++ b/InvoiceReminder.API.UnitTests/InvoiceReminder.API.UnitTests.csproj @@ -16,6 +16,7 @@ + diff --git a/InvoiceReminder.API/Endpoints/GoogleOAuthEndpoints.cs b/InvoiceReminder.API/Endpoints/GoogleOAuthEndpoints.cs index 7ae0618..54993c1 100644 --- a/InvoiceReminder.API/Endpoints/GoogleOAuthEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/GoogleOAuthEndpoints.cs @@ -4,11 +4,19 @@ namespace InvoiceReminder.API.Endpoints; public class GoogleOAuthEndpoints : IEndpointDefinition { + private const string basepath = "/api/google_oauth"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - var basepath = "/api/google_oauth"; var endpoint = endpoints.MapGroup(basepath).WithName("GoogleOAuthEndpoints"); + MapGetAuthUrl(endpoint); + MapAuthorize(endpoint); + MapRevoke(endpoint); + } + + private static void MapGetAuthUrl(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/get-auth-url/{id}", (IGoogleOAuthService oAuthService, Guid id) => { var result = oAuthService.GetAuthorizationUrl(id.ToString()); @@ -22,7 +30,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapAuthorize(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/authorize", async (IGoogleOAuthService oAuthService, CancellationToken ct, Guid state, string code) => { @@ -37,7 +48,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapRevoke(RouteGroupBuilder endpoint) + { _ = endpoint.MapDelete("/revoke", async (IGoogleOAuthService oAuthService, CancellationToken ct, Guid id) => { var result = await oAuthService.RevokeAuthorizationAsync(id, ct); diff --git a/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs b/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs index b22ca2a..a4c3957 100644 --- a/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs @@ -6,11 +6,22 @@ namespace InvoiceReminder.API.Endpoints; public class InvoiceEndpoints : IEndpointDefinition { + private const string basepath = "/api/invoice"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - var basepath = "/api/invoice"; var endpoint = endpoints.MapGroup(basepath).WithName("InvoiceEndpoints"); + MapGetInvoices(endpoint); + MapGetInvoice(endpoint); + MapGetInvoiceByBarcode(endpoint); + MapCreateInvoice(endpoint); + MapUpdateInvoice(endpoint); + MapDeleteInvoice(endpoint); + } + + private static void MapGetInvoices(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/", (IInvoiceAppService invoiceAppService) => { var result = invoiceAppService.GetAll(); @@ -24,7 +35,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetInvoice(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/{id}", async (IInvoiceAppService invoiceAppService, CancellationToken ct, Guid id) => { var result = await invoiceAppService.GetByIdAsync(id, ct); @@ -38,7 +52,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetInvoiceByBarcode(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/getby-barcode/{value}", async (IInvoiceAppService invoiceAppService, CancellationToken ct, string value) => { @@ -53,7 +70,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapCreateInvoice(RouteGroupBuilder endpoint) + { _ = endpoint.MapPost("/", async (IInvoiceAppService invoiceAppService, CancellationToken ct, [FromBody] InvoiceViewModel invoiceViewModel) => { @@ -68,7 +88,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status201Created) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapUpdateInvoice(RouteGroupBuilder endpoint) + { _ = endpoint.MapPut("/", async (IInvoiceAppService invoiceAppService, CancellationToken ct, [FromBody] InvoiceViewModel invoiceViewModel) => { @@ -83,7 +106,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapDeleteInvoice(RouteGroupBuilder endpoint) + { _ = endpoint.MapDelete("/", async (IInvoiceAppService invoiceAppService, CancellationToken ct, [FromBody] InvoiceViewModel invoiceViewModel) => { diff --git a/InvoiceReminder.API/Endpoints/JobScheduleEndpoints.cs b/InvoiceReminder.API/Endpoints/JobScheduleEndpoints.cs index 9f7e9c9..2db5d02 100644 --- a/InvoiceReminder.API/Endpoints/JobScheduleEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/JobScheduleEndpoints.cs @@ -6,11 +6,22 @@ namespace InvoiceReminder.API.Endpoints; public class JobScheduleEndpoints : IEndpointDefinition { + private const string basepath = "/api/job_schedule"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - var basepath = "/api/job_schedule"; var endpoint = endpoints.MapGroup(basepath).WithName("JobScheduleEndpoints"); + MapGetJobSchedules(endpoint); + MapGetJobSchedule(endpoint); + MapGetJobScheduleByUserId(endpoint); + MapCreateJobSchedule(endpoint); + MapUpdateJobSchedule(endpoint); + MapDeleteJobSchedule(endpoint); + } + + private static void MapGetJobSchedules(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/", (IJobScheduleAppService jobScheduleAppService) => { var result = jobScheduleAppService.GetAll(); @@ -24,7 +35,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetJobSchedule(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/{id}", async (IJobScheduleAppService jobScheduleAppService, CancellationToken ct, Guid id) => { var result = await jobScheduleAppService.GetByIdAsync(id, ct); @@ -39,7 +53,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetJobScheduleByUserId(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/getby-userid/{id}", async (IJobScheduleAppService jobScheduleAppService, CancellationToken ct, Guid id) => { @@ -55,10 +72,12 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapCreateJobSchedule(RouteGroupBuilder endpoint) + { _ = endpoint.MapPost("/", - async (IJobScheduleAppService jobScheduleAppService, - CancellationToken ct, + async (IJobScheduleAppService jobScheduleAppService, CancellationToken ct, [FromBody] JobScheduleViewModel jobScheduleViewModel) => { var result = await jobScheduleAppService.AddNewJobAsync(jobScheduleViewModel, ct); @@ -72,10 +91,12 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status201Created) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapUpdateJobSchedule(RouteGroupBuilder endpoint) + { _ = endpoint.MapPut("/", - async (IJobScheduleAppService jobScheduleAppService, - CancellationToken ct, + async (IJobScheduleAppService jobScheduleAppService, CancellationToken ct, [FromBody] JobScheduleViewModel jobScheduleViewModel) => { var result = await jobScheduleAppService.UpdateAsync(jobScheduleViewModel, ct); @@ -89,10 +110,12 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapDeleteJobSchedule(RouteGroupBuilder endpoint) + { _ = endpoint.MapDelete("/", - async (IJobScheduleAppService jobScheduleAppService, - CancellationToken ct, + async (IJobScheduleAppService jobScheduleAppService, CancellationToken ct, [FromBody] JobScheduleViewModel jobScheduleViewModel) => { var result = await jobScheduleAppService.RemoveAsync(jobScheduleViewModel, ct); diff --git a/InvoiceReminder.API/Endpoints/LoginEndpoints.cs b/InvoiceReminder.API/Endpoints/LoginEndpoints.cs index ca8c445..fe65f0b 100644 --- a/InvoiceReminder.API/Endpoints/LoginEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/LoginEndpoints.cs @@ -8,9 +8,18 @@ namespace InvoiceReminder.API.Endpoints; public class LoginEndpoints : IEndpointDefinition { + private const string basepath = "/api/login"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - _ = endpoints.MapPost("/api/login", + var endpoint = endpoints.MapGroup(basepath).WithName("LoginEndpoints"); + + MapLogin(endpoint); + } + + private static void MapLogin(IEndpointRouteBuilder endpoints) + { + _ = endpoints.MapPost("/", async (IJwtProvider jwtProvider, IUserAppService userAppService, CancellationToken ct, diff --git a/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs b/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs index 963265d..e305be5 100644 --- a/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs @@ -6,11 +6,23 @@ namespace InvoiceReminder.API.Endpoints; public class ScanEmailDefinitionEndpoints : IEndpointDefinition { + private const string basepath = "/api/scan_email"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - var basepath = "/api/scan_email"; var endpoint = endpoints.MapGroup(basepath).WithName("ScanEmailDefinitionEndpoints"); + MapGetScanEmailDefinitions(endpoint); + MapGetScanEmailDefinition(endpoint); + MapGetByUserId(endpoint); + MapGetBySenderEmailAddress(endpoint); + MapCreateScanEmailDefinition(endpoint); + MapUpdateScanEmailDefinition(endpoint); + MapDeleteScanEmailDefinition(endpoint); + } + + private static void MapGetScanEmailDefinitions(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/", (IScanEmailDefinitionAppService scanEmailDefinitionAppService) => { var result = scanEmailDefinitionAppService.GetAll(); @@ -24,7 +36,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetScanEmailDefinition(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/{id}", async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, CancellationToken ct, Guid id) => { @@ -39,7 +54,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetByUserId(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/getby-userid/{id}", async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, CancellationToken ct, Guid id) => { @@ -54,7 +72,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetBySenderEmailAddress(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/{email}/{id}", async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, CancellationToken ct, @@ -72,7 +93,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapCreateScanEmailDefinition(RouteGroupBuilder endpoint) + { _ = endpoint.MapPost("/", async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, CancellationToken ct, @@ -89,7 +113,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status201Created) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapUpdateScanEmailDefinition(RouteGroupBuilder endpoint) + { _ = endpoint.MapPut("/", async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, CancellationToken ct, @@ -106,10 +133,12 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapDeleteScanEmailDefinition(RouteGroupBuilder endpoint) + { _ = endpoint.MapDelete("/", - async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, - CancellationToken ct, + async (IScanEmailDefinitionAppService scanEmailDefinitionAppService, CancellationToken ct, [FromBody] ScanEmailDefinitionViewModel scanEmailDefinitionViewModel) => { var result = await scanEmailDefinitionAppService.RemoveAsync(scanEmailDefinitionViewModel, ct); diff --git a/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs b/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs index ded320c..7cb692a 100644 --- a/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs @@ -4,9 +4,18 @@ namespace InvoiceReminder.API.Endpoints; public class SendMessageEndpoints : IEndpointDefinition { + private const string basepath = "/api/send_message"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - _ = endpoints.MapGet("/api/send_message/{id}", + var endpoint = endpoints.MapGroup(basepath).WithName("SendMessageEndpoints"); + + MapSendMessage(endpoint); + } + + private static void MapSendMessage(RouteGroupBuilder endpoint) + { + _ = endpoint.MapGet("/{id}", async (ISendMessageService messageService, CancellationToken ct, Guid id) => { var result = await messageService.SendMessage(id, ct); diff --git a/InvoiceReminder.API/Endpoints/UserEndpoints.cs b/InvoiceReminder.API/Endpoints/UserEndpoints.cs index 1a41bbb..1981c9c 100644 --- a/InvoiceReminder.API/Endpoints/UserEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/UserEndpoints.cs @@ -7,11 +7,23 @@ namespace InvoiceReminder.API.Endpoints; public class UserEndpoints : IEndpointDefinition { + private const string basepath = "/api/user"; + public void RegisterEndpoints(IEndpointRouteBuilder endpoints) { - var basepath = "/api/user"; var endpoint = endpoints.MapGroup(basepath).WithName("UserEndpoints"); + MapGetUsers(endpoint); + MapGetUser(endpoint); + MapGetUserByEmail(endpoint); + MapCreateUser(endpoint); + MapCreateUsers(endpoint); + MapUpdateUser(endpoint); + MapDeleteUser(endpoint); + } + + private static void MapGetUsers(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/", (IUserAppService userAppService) => { var result = userAppService.GetAll(); @@ -25,21 +37,27 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetUser(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/{id}", async (IUserAppService userAppService, CancellationToken ct, Guid id) => - { - var result = await userAppService.GetByIdAsync(id, ct); + { + var result = await userAppService.GetByIdAsync(id, ct); - return result.IsSuccess - ? Results.Ok(result.Value) - : Results.NotFound(result.Error); - }) + return result.IsSuccess + ? Results.Ok(result.Value) + : Results.NotFound(result.Error); + }) .WithName("GetUser") .RequireAuthorization() .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapGetUserByEmail(RouteGroupBuilder endpoint) + { _ = endpoint.MapGet("/getby-email/{value}", async (IUserAppService userAppService, CancellationToken ct, string value) => { @@ -54,7 +72,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapCreateUser(RouteGroupBuilder endpoint) + { _ = endpoint.MapPost("/", async (IUserAppService userAppService, CancellationToken ct, [FromBody] UserViewModel userViewModel) => { @@ -71,7 +92,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status201Created) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapCreateUsers(RouteGroupBuilder endpoint) + { _ = endpoint.MapPost("/bulk-insert", async (IUserAppService userAppService, CancellationToken ct, [FromBody] ICollection usersViewModel) => { @@ -91,7 +115,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status201Created) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapUpdateUser(RouteGroupBuilder endpoint) + { _ = endpoint.MapPut("/", async (IUserAppService userAppService, CancellationToken ct, [FromBody] UserViewModel userViewModel) => { @@ -106,7 +133,10 @@ public void RegisterEndpoints(IEndpointRouteBuilder endpoints) .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) .Produces(StatusCodes.Status500InternalServerError); + } + private static void MapDeleteUser(RouteGroupBuilder endpoint) + { _ = endpoint.MapDelete("/", async (IUserAppService userAppService, CancellationToken ct, [FromBody] UserViewModel userViewModel) => { diff --git a/InvoiceReminder.API/Exceptions/GlobalExceptionHandler.cs b/InvoiceReminder.API/Exceptions/GlobalExceptionHandler.cs index e8b1f21..e400371 100644 --- a/InvoiceReminder.API/Exceptions/GlobalExceptionHandler.cs +++ b/InvoiceReminder.API/Exceptions/GlobalExceptionHandler.cs @@ -16,7 +16,10 @@ public GlobalExceptionHandler(IProblemDetailsService problemDetailsService, ILog public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { - _logger.LogError(exception, "An Exception occurred: {Message}", exception.Message); + if (_logger.IsEnabled(LogLevel.Error)) + { + _logger.LogError(exception, "An Exception occurred: {Message}", exception.Message); + } httpContext.Response.StatusCode = exception switch { diff --git a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs index 7e257f1..627bcf4 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Application.AppServices; using InvoiceReminder.Data.Interfaces; using Mapster; @@ -13,6 +14,9 @@ public sealed class BaseAppServiceTests private readonly IBaseRepository _repository; private readonly IUnitOfWork _unitOfWork; + private readonly Faker _entityFaker; + private readonly Faker _entityViewModelFaker; + public TestContext TestContext { get; set; } public BaseAppServiceTests() @@ -20,13 +24,19 @@ public BaseAppServiceTests() _repository = Substitute.For>(); _unitOfWork = Substitute.For(); _appService = new BaseAppService(_repository, _unitOfWork); + + _entityFaker = new Faker() + .RuleFor(e => e.Name, faker => faker.Person.FullName); + + _entityViewModelFaker = new Faker() + .RuleFor(e => e.Name, faker => faker.Person.FullName); } [TestMethod] public async Task AddAsync_Should_Return_Success_When_Entity_Is_Valid() { // Arrange - var viewModel = new TestEntityViewModel { Name = "Test" }; + var viewModel = _entityViewModelFaker.Generate(); _ = _repository.AddAsync(Arg.Any(), Arg.Any()) .Returns(viewModel.Adapt()); @@ -82,11 +92,7 @@ public async Task BulkInsertAsync_Should_Return_Failure_When_ViewModels_Are_Null public async Task BulkInsertAsync_Should_Return_Success_When_ViewModels_Are_Valid() { // Arrange - var viewModels = new List - { - new() { Name = "Test1" }, - new() { Name = "Test2" } - }; + var viewModels = _entityViewModelFaker.Generate(2); _ = _repository.BulkInsertAsync(Arg.Any>(), Arg.Any()) .Returns(viewModels.Count); @@ -131,11 +137,7 @@ public void GetAll_Should_Return_Failure_When_No_Entities_Exist() public void GetAll_Should_Return_Success_When_Entities_Exist() { // Arrange - var entities = new List - { - new() { Name = "Entity1" }, - new() { Name = "Entity2" } - }; + var entities = _entityFaker.Generate(2); _ = _repository.GetAll().Returns(entities); @@ -157,13 +159,12 @@ public void GetAll_Should_Return_Success_When_Entities_Exist() public async Task GetByIdAsync_Should_Return_Success_When_Entity_Exists() { // Arrange - var id = Guid.Parse("42ab20e5-0742-4d32-a76e-7c45fd74dac3"); - var entity = new TestEntity { Name = "Test" }; + var entity = _entityFaker.Generate(); _ = _repository.GetByIdAsync(Arg.Any(), Arg.Any()).Returns(entity); // Act - var result = await _appService.GetByIdAsync(id, TestContext.CancellationToken); + var result = await _appService.GetByIdAsync(Guid.NewGuid(), TestContext.CancellationToken); // Assert _ = _repository.Received(1).GetByIdAsync(Arg.Any(), Arg.Any()); @@ -180,7 +181,8 @@ public async Task GetByIdAsync_Should_Return_Success_When_Entity_Exists() public async Task GetByIdAsync_Should_Return_Failure_When_Entity_Does_Not_Exist() { // Arrange - var id = Guid.Parse("42ab20e5-0742-4d32-a76e-7c45fd74dac3"); + var id = Guid.NewGuid(); + _ = _repository.GetByIdAsync(Arg.Any(), Arg.Any()) .Returns(Task.FromResult(null)); @@ -202,7 +204,7 @@ public async Task GetByIdAsync_Should_Return_Failure_When_Entity_Does_Not_Exist( public async Task RemoveAsync_Should_Return_Success_When_Entity_Exists() { // Arrange - var entity = new TestEntityViewModel { Name = "Test" }; + var entity = _entityViewModelFaker.Generate(); _repository.Remove(Arg.Any()); _ = _unitOfWork.SaveChangesAsync(Arg.Any()).Returns(Task.CompletedTask); @@ -239,7 +241,7 @@ public async Task RemoveAsync_Should_Return_Failure_When_ViewModel_Is_Null() public async Task UpdateAsync_Should_Return_Success_When_ViewModel_Is_Valid() { // Arrange - var viewModel = new TestEntityViewModel { Name = "Updated" }; + var viewModel = _entityViewModelFaker.Generate(); _ = _repository.Update(Arg.Any()).Returns(viewModel.Adapt()); _ = _unitOfWork.SaveChangesAsync(Arg.Any()).Returns(Task.CompletedTask); @@ -274,12 +276,12 @@ public async Task UpdateAsync_Should_Return_Failure_When_ViewModel_Is_Null() } } -public class TestEntity +public sealed class TestEntity { public string Name { get; set; } } -public class TestEntityViewModel +public sealed class TestEntityViewModel { public string Name { get; set; } } diff --git a/InvoiceReminder.Application.UnitTests/AppServices/EmailAuthTokenAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/EmailAuthTokenAppServiceTests.cs index 209835a..bec2386 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/EmailAuthTokenAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/EmailAuthTokenAppServiceTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Application.AppServices; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Data.Interfaces; @@ -12,6 +13,7 @@ public sealed class EmailAuthTokenAppServiceTests { private readonly IEmailAuthTokenRepository _repository; private readonly IUnitOfWork _unitOfWork; + private readonly Faker _faker; public TestContext TestContext { get; set; } @@ -19,6 +21,21 @@ public EmailAuthTokenAppServiceTests() { _repository = Substitute.For(); _unitOfWork = Substitute.For(); + _faker = new Faker(); + } + + private static Faker CreateEmailAuthTokenFaker() + { + return new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.UserId, faker => faker.Random.Guid()) + .RuleFor(e => e.AccessToken, faker => faker.Random.AlphaNumeric(128)) + .RuleFor(e => e.RefreshToken, faker => faker.Random.AlphaNumeric(128)) + .RuleFor(e => e.TokenProvider, faker => faker.PickRandom("Google", "Microsoft", "GitHub")) + .RuleFor(e => e.NonceValue, faker => faker.Random.Hash()) + .RuleFor(e => e.AccessTokenExpiry, faker => faker.Date.Future().ToUniversalTime()) + .RuleFor(e => e.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(e => e.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } [TestMethod] @@ -41,19 +58,12 @@ public async Task GetByUserIdAsync_WhenTokenExists_ShouldReturnSuccess_WithResul { // Arrange var appService = new EmailAuthTokenAppService(_repository, _unitOfWork); - var userId = Guid.NewGuid(); + var userId = _faker.Random.Guid(); var tokenProvider = "Google"; - var emailAuthToken = new EmailAuthToken - { - Id = Guid.NewGuid(), - UserId = userId, - AccessToken = "access_token", - RefreshToken = "refresh_token", - TokenProvider = "Google", - AccessTokenExpiry = DateTime.UtcNow.AddHours(1), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; + var emailAuthToken = CreateEmailAuthTokenFaker() + .RuleFor(e => e.UserId, userId) + .RuleFor(e => e.TokenProvider, tokenProvider) + .Generate(); _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(emailAuthToken); @@ -78,7 +88,7 @@ public async Task GetByUserIdAsync_WhenTokenDoesNotExist_ShouldReturnFailure_Wit { // Arrange var appService = new EmailAuthTokenAppService(_repository, _unitOfWork); - var userId = Guid.NewGuid(); + var userId = _faker.Random.Guid(); var tokenProvider = "Google"; _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any(), Arg.Any()) diff --git a/InvoiceReminder.Application.UnitTests/AppServices/InvoiceAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/InvoiceAppServiceTests.cs index 817b712..de971ac 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/InvoiceAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/InvoiceAppServiceTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Application.AppServices; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Application.ViewModels; @@ -13,6 +14,7 @@ public sealed class InvoiceAppServiceTests { private readonly IInvoiceRepository _repository; private readonly IUnitOfWork _unitOfWork; + private readonly Faker _faker; public TestContext TestContext { get; set; } @@ -20,6 +22,29 @@ public InvoiceAppServiceTests() { _repository = Substitute.For(); _unitOfWork = Substitute.For(); + _faker = new Faker(); + } + + private static Faker CreateInvoiceFaker() + { + return new Faker() + .RuleFor(i => i.Id, faker => faker.Random.Guid()) + .RuleFor(i => i.UserId, faker => faker.Random.Guid()) + .RuleFor(i => i.Bank, faker => faker.PickRandom( + "Banco do Brasil", + "Bradesco", + "Itaú", + "Caixa Econômica Federal", + "Santander", + "Safra", + "Citibank", + "BTG Pactual")) + .RuleFor(i => i.Beneficiary, faker => faker.Person.FullName) + .RuleFor(i => i.Amount, faker => faker.Finance.Amount(10, 10000)) + .RuleFor(i => i.Barcode, faker => faker.Random.AlphaNumeric(44)) + .RuleFor(i => i.DueDate, faker => faker.Date.Future().ToUniversalTime()) + .RuleFor(i => i.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(i => i.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } [TestMethod] @@ -42,16 +67,10 @@ public async Task GetByBarcodeAsync_WhenInvoiceExists_ShouldReturnSuccess_WithRe { // Arrange var appService = new InvoiceAppService(_repository, _unitOfWork); - var barcode = "12345678901234567890"; - var invoice = new Invoice - { - Id = Guid.NewGuid(), - Barcode = barcode, - Amount = 100.00m, - DueDate = DateTime.UtcNow.AddDays(30), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; + var barcode = _faker.Random.AlphaNumeric(44); + var invoice = CreateInvoiceFaker() + .RuleFor(i => i.Barcode, barcode) + .Generate(); _ = _repository.GetByBarcodeAsync(Arg.Any(), Arg.Any()).Returns(invoice); @@ -76,7 +95,7 @@ public async Task GetByBarcodeAsync_WhenInvoiceDoesNotExist_ShouldReturnFailure_ { // Arrange var appService = new InvoiceAppService(_repository, _unitOfWork); - var barcode = "12345678901234567890"; + var barcode = _faker.Random.AlphaNumeric(44); _ = _repository.GetByBarcodeAsync(Arg.Any(), Arg.Any()).Returns((Invoice)null); diff --git a/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs index 68c9231..83c8c47 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Application.AppServices; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Application.ViewModels; @@ -17,6 +18,7 @@ public sealed class JobScheduleAppServiceTests private readonly IUnitOfWork _unitOfWork; private readonly IJobFactory _jobFactory; private readonly ISchedulerFactory _schedulerFactory; + private readonly Faker _faker; public TestContext TestContext { get; set; } @@ -26,6 +28,41 @@ public JobScheduleAppServiceTests() _unitOfWork = Substitute.For(); _jobFactory = Substitute.For(); _schedulerFactory = Substitute.For(); + _faker = new Faker(); + } + + private static Faker CreateJobScheduleFaker() + { + return new Faker() + .RuleFor(j => j.Id, faker => faker.Random.Guid()) + .RuleFor(j => j.UserId, faker => faker.Random.Guid()) + .RuleFor(j => j.CronExpression, faker => faker.PickRandom( + "0 0/5 * * * ?", // Every 5 minutes + "0 0 * * * ?", // Every hour + "0 0 0 * * ?", // Every day at midnight + "0 0 0 ? * MON", // Every Monday + "0 0 0 1 * ?", // First day of month + "0 0 0 1 1 ?", // Every January 1st + "0 0 12 * * ?")) // Every noon + .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); + } + + private static Faker CreateJobScheduleViewModelFaker() + { + return new Faker() + .RuleFor(j => j.Id, faker => faker.Random.Guid()) + .RuleFor(j => j.UserId, faker => faker.Random.Guid()) + .RuleFor(j => j.CronExpression, faker => faker.PickRandom( + "0 0/5 * * * ?", + "0 0 * * * ?", + "0 0 0 * * ?", + "0 0 0 ? * MON", + "0 0 0 1 * ?", + "0 0 0 1 1 ?", + "0 0 12 * * ?")) + .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } [TestMethod] @@ -70,14 +107,7 @@ public async Task AddNewJobAsync_ShouldReturnSuccess_WhenViewModelIsValid() { // Arrange var appService = new JobScheduleAppService(_repository, _schedulerFactory, _jobFactory, _unitOfWork); - var viewModel = new JobScheduleViewModel - { - Id = Guid.NewGuid(), - UserId = Guid.NewGuid(), - CronExpression = "0 0/5 * * * ?", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; + var viewModel = CreateJobScheduleViewModelFaker().Generate(); // Act var result = await appService.AddNewJobAsync(viewModel, TestContext.CancellationToken); @@ -103,17 +133,11 @@ public async Task GetByUserIdAsync_ShouldReturnSuccess_WhenUserHasJobSchedules() { // Arrange var appService = new JobScheduleAppService(_repository, _schedulerFactory, _jobFactory, _unitOfWork); - var userId = Guid.NewGuid(); - var jobSchedules = new List - { - new() { - Id = Guid.NewGuid(), - UserId = userId, - CronExpression = "0 0/5 * * * ?", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - } - }; + var userId = _faker.Random.Guid(); + var jobSchedules = CreateJobScheduleFaker() + .RuleFor(j => j.UserId, userId) + .Generate(3) + .ToList(); _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any()).Returns(jobSchedules); @@ -138,7 +162,7 @@ public async Task GetByUserIdAsync_ShouldReturnFailure_WhenUserHasNoJobSchedules { // Arrange var appService = new JobScheduleAppService(_repository, _schedulerFactory, _jobFactory, _unitOfWork); - var userId = Guid.NewGuid(); + var userId = _faker.Random.Guid(); _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any()).Returns([]); diff --git a/InvoiceReminder.Application.UnitTests/AppServices/ScanEmailDefinitionAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/ScanEmailDefinitionAppServiceTests.cs index 5714ede..b391a19 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/ScanEmailDefinitionAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/ScanEmailDefinitionAppServiceTests.cs @@ -1,8 +1,10 @@ +using Bogus; using InvoiceReminder.Application.AppServices; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Application.ViewModels; using InvoiceReminder.Data.Interfaces; using InvoiceReminder.Domain.Entities; +using InvoiceReminder.Domain.Enums; using Mapster; using NSubstitute; using Shouldly; @@ -14,6 +16,7 @@ public sealed class ScanEmailDefinitionAppServiceTests { private readonly IScanEmailDefinitionRepository _repository; private readonly IUnitOfWork _unitOfWork; + private readonly Faker _faker; public TestContext TestContext { get; set; } @@ -21,6 +24,21 @@ public ScanEmailDefinitionAppServiceTests() { _repository = Substitute.For(); _unitOfWork = Substitute.For(); + _faker = new Faker(); + } + + private static Faker CreateScanEmailDefinitionFaker() + { + return new Faker() + .RuleFor(s => s.Id, faker => faker.Random.Guid()) + .RuleFor(s => s.UserId, faker => faker.Random.Guid()) + .RuleFor(s => s.InvoiceType, faker => faker.PickRandom()) + .RuleFor(s => s.Beneficiary, faker => faker.Person.FullName) + .RuleFor(s => s.Description, faker => faker.Lorem.Sentence()) + .RuleFor(s => s.SenderEmailAddress, faker => faker.Internet.Email()) + .RuleFor(s => s.AttachmentFileName, faker => faker.System.FileName("pdf")) + .RuleFor(s => s.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(s => s.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } [TestMethod] @@ -43,19 +61,12 @@ public async Task GetBySenderBeneficiaryAsync_WhenSenderBeneficiaryExists_Should { // Arrange var appService = new ScanEmailDefinitionAppService(_repository, _unitOfWork); - var beneficiary = "Test Beneficiary"; - var userId = Guid.NewGuid(); - var scanEmailDefinition = new ScanEmailDefinition - { - Id = Guid.NewGuid(), - UserId = userId, - AttachmentFileName = "test.pdf", - Beneficiary = beneficiary, - Description = "Test Description", - SenderEmailAddress = "test@mail.com", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; + var userId = _faker.Random.Guid(); + var beneficiary = _faker.Person.FullName; + var scanEmailDefinition = CreateScanEmailDefinitionFaker() + .RuleFor(s => s.UserId, userId) + .RuleFor(s => s.Beneficiary, beneficiary) + .Generate(); _ = _repository.GetBySenderBeneficiaryAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(scanEmailDefinition); @@ -82,8 +93,8 @@ public async Task GetBySenderBeneficiaryAsync_WhenSenderBeneficiaryNotExists_Sho { // Arrange var appService = new ScanEmailDefinitionAppService(_repository, _unitOfWork); - var beneficiary = "Test Beneficiary"; - var userId = Guid.NewGuid(); + var beneficiary = _faker.Person.FullName; + var userId = _faker.Random.Guid(); _ = _repository.GetBySenderBeneficiaryAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns((ScanEmailDefinition)null); @@ -109,25 +120,18 @@ public async Task GetBySenderEmailAddressAsync_WhenSenderEmailAddressExists_Shou { // Arrange var appService = new ScanEmailDefinitionAppService(_repository, _unitOfWork); - var beneficiary = "test@email.com"; - var userId = Guid.NewGuid(); - var scanEmailDefinition = new ScanEmailDefinition - { - Id = Guid.NewGuid(), - UserId = userId, - AttachmentFileName = "test.pdf", - Beneficiary = beneficiary, - Description = "Test Description", - SenderEmailAddress = "test@mail.com", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; + var userId = _faker.Random.Guid(); + var senderEmail = _faker.Internet.Email(); + var scanEmailDefinition = CreateScanEmailDefinitionFaker() + .RuleFor(s => s.UserId, userId) + .RuleFor(s => s.SenderEmailAddress, senderEmail) + .Generate(); _ = _repository.GetBySenderEmailAddressAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(scanEmailDefinition); // Act - var result = await appService.GetBySenderEmailAddressAsync(beneficiary, userId, TestContext.CancellationToken); + var result = await appService.GetBySenderEmailAddressAsync(senderEmail, userId, TestContext.CancellationToken); // Assert _ = _repository.Received(1) @@ -148,14 +152,14 @@ public async Task GetBySenderEmailAddressAsync_WhenSenderEmailAddressNotExists_S { // Arrange var appService = new ScanEmailDefinitionAppService(_repository, _unitOfWork); - var beneficiary = "not_existing@email.com"; - var userId = Guid.NewGuid(); + var senderEmail = _faker.Internet.Email(); + var userId = _faker.Random.Guid(); _ = _repository.GetBySenderEmailAddressAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns((ScanEmailDefinition)null); // Act - var result = await appService.GetBySenderEmailAddressAsync(beneficiary, userId, TestContext.CancellationToken); + var result = await appService.GetBySenderEmailAddressAsync(senderEmail, userId, TestContext.CancellationToken); // Assert _ = _repository.Received(1) @@ -175,21 +179,11 @@ public async Task GetByUserIdAsync_WhenUserIdExists_ShouldReturnSuccess_WithResu { // Arrange var appService = new ScanEmailDefinitionAppService(_repository, _unitOfWork); - var userId = Guid.NewGuid(); - var scanEmailDefinitions = new List - { - new() - { - Id = Guid.NewGuid(), - UserId = userId, - AttachmentFileName = "test.pdf", - Beneficiary = "Test Beneficiary", - Description = "Test Description", - SenderEmailAddress = "test@mail.com", - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - } - }; + var userId = _faker.Random.Guid(); + var scanEmailDefinitions = CreateScanEmailDefinitionFaker() + .RuleFor(s => s.UserId, userId) + .Generate(3) + .ToList(); _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any()).Returns(scanEmailDefinitions); @@ -214,7 +208,7 @@ public async Task GetByUserIdAsync_WhenUserIdNotExists_ShouldReturnFailure_WithR { // Arrange var appService = new ScanEmailDefinitionAppService(_repository, _unitOfWork); - var userId = Guid.NewGuid(); + var userId = _faker.Random.Guid(); _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any()).Returns([]); // Act diff --git a/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs index 3f742af..6216551 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Application.AppServices; using InvoiceReminder.Application.Interfaces; using InvoiceReminder.Application.ViewModels; @@ -14,6 +15,7 @@ public sealed class UserAppServiceTests { private readonly IUserRepository _repository; private readonly IUnitOfWork _unitOfWork; + private readonly Faker _faker; public TestContext TestContext { get; set; } @@ -21,6 +23,19 @@ public UserAppServiceTests() { _repository = Substitute.For(); _unitOfWork = Substitute.For(); + _faker = new Faker(); + } + + private static Faker CreateUserFaker() + { + return new Faker() + .RuleFor(u => u.Id, faker => faker.Random.Guid()) + .RuleFor(u => u.Name, faker => faker.Person.FullName) + .RuleFor(u => u.Email, faker => faker.Internet.Email()) + .RuleFor(u => u.Password, faker => faker.Random.AlphaNumeric(32)) + .RuleFor(u => u.TelegramChatId, faker => faker.Random.Long(1000000, 9999999999)) + .RuleFor(u => u.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(u => u.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } [TestMethod] @@ -43,18 +58,10 @@ public async Task GetByEmaildAsync_WhenUserEmailExists_ShouldReturnSuccess_Whith { // Arrange var appService = new UserAppService(_repository, _unitOfWork); - var email = "user@test.com"; - var user = new User - { - Id = Guid.NewGuid(), - Email = email, - Name = "Test User", - Password = "password", - JobSchedules = [], - ScanEmailDefinitions = [], - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; + var email = _faker.Internet.Email(); + var user = CreateUserFaker() + .RuleFor(u => u.Email, email) + .Generate(); _ = _repository.GetByEmailAsync(Arg.Any(), Arg.Any()).Returns(user); @@ -79,7 +86,7 @@ public async Task GetByEmaildAsync_WhenUserEmailNotExists_ShouldReturnFailure_Wh { // Arrange var appService = new UserAppService(_repository, _unitOfWork); - var email = "not_existing@test.com"; + var email = _faker.Internet.Email(); _ = _repository.GetByEmailAsync(Arg.Any(), Arg.Any()).Returns((User)null); diff --git a/InvoiceReminder.Application.UnitTests/InvoiceReminder.Application.UnitTests.csproj b/InvoiceReminder.Application.UnitTests/InvoiceReminder.Application.UnitTests.csproj index fa4d5f2..a65a181 100644 --- a/InvoiceReminder.Application.UnitTests/InvoiceReminder.Application.UnitTests.csproj +++ b/InvoiceReminder.Application.UnitTests/InvoiceReminder.Application.UnitTests.csproj @@ -16,6 +16,7 @@ + all diff --git a/InvoiceReminder.Data/InvoiceReminder.Data.csproj b/InvoiceReminder.Data/InvoiceReminder.Data.csproj index 05981c8..b35eebb 100644 --- a/InvoiceReminder.Data/InvoiceReminder.Data.csproj +++ b/InvoiceReminder.Data/InvoiceReminder.Data.csproj @@ -6,7 +6,8 @@ - + + diff --git a/InvoiceReminder.Data/Repository/BaseRepository.cs b/InvoiceReminder.Data/Repository/BaseRepository.cs index bd3c10c..236d3da 100644 --- a/InvoiceReminder.Data/Repository/BaseRepository.cs +++ b/InvoiceReminder.Data/Repository/BaseRepository.cs @@ -1,3 +1,4 @@ +using EFCore.BulkExtensions; using InvoiceReminder.Data.Interfaces; using Microsoft.EntityFrameworkCore; using System.Linq.Expressions; @@ -33,7 +34,7 @@ public virtual async Task BulkInsertAsync(ICollection entities, Ca entity.GetType().GetProperty("UpdatedAt")?.SetValue(entity, DateTime.UtcNow); } - await _dbContext.BulkInsertAsync(entities, cancellationToken); + await _dbContext.BulkInsertAsync(entities, cancellationToken: cancellationToken); return entities.Count; } diff --git a/InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs b/InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs index 8661c98..740e9e9 100644 --- a/InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs +++ b/InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Domain.Extensions; using Shouldly; @@ -12,6 +13,10 @@ private sealed class TestEntity public string Name { get; init; } = string.Empty; } + private readonly Faker _entityFaker = new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.Name, faker => faker.Person.FullName); + [TestMethod] public void AddIfNotExists_WhenEntityIsNull_ShouldNotAddToCollection() { @@ -30,8 +35,7 @@ public void AddIfNotExists_WhenEntityIsNull_ShouldNotAddToCollection() public void AddIfNotExists_WhenCollectionIsEmpty_ShouldAddEntity() { // Arrange - var entityId = Guid.NewGuid(); - var entity = new TestEntity { Id = entityId, Name = "Test Entity" }; + var entity = _entityFaker.Generate(); var collection = new List(); // Act @@ -42,7 +46,7 @@ public void AddIfNotExists_WhenCollectionIsEmpty_ShouldAddEntity() { _ = collection.ShouldHaveSingleItem(); collection[0].ShouldBeEquivalentTo(entity); - collection[0].Id.ShouldBe(entityId); + collection[0].Id.ShouldBe(entity.Id); }); } @@ -50,9 +54,10 @@ public void AddIfNotExists_WhenCollectionIsEmpty_ShouldAddEntity() public void AddIfNotExists_WhenEntityAlreadyExists_ShouldNotAddDuplicate() { // Arrange - var entityId = Guid.NewGuid(); - var existingEntity = new TestEntity { Id = entityId, Name = "Existing Entity" }; - var newEntity = new TestEntity { Id = entityId, Name = "New Entity" }; + var faker = new Faker(); + var entityId = faker.Random.Guid(); + var existingEntity = new TestEntity { Id = entityId, Name = faker.Person.FullName }; + var newEntity = new TestEntity { Id = entityId, Name = faker.Person.FullName }; var collection = new List { existingEntity }; // Act @@ -63,7 +68,7 @@ public void AddIfNotExists_WhenEntityAlreadyExists_ShouldNotAddDuplicate() { _ = collection.ShouldHaveSingleItem(); collection[0].ShouldBeEquivalentTo(existingEntity); - collection[0].Name.ShouldBe("Existing Entity"); + collection[0].Id.ShouldBe(entityId); }); } @@ -71,10 +76,8 @@ public void AddIfNotExists_WhenEntityAlreadyExists_ShouldNotAddDuplicate() public void AddIfNotExists_WhenEntityDoesNotExist_ShouldAddToNonEmptyCollection() { // Arrange - var existingId = Guid.NewGuid(); - var newId = Guid.NewGuid(); - var existingEntity = new TestEntity { Id = existingId, Name = "Existing Entity" }; - var newEntity = new TestEntity { Id = newId, Name = "New Entity" }; + var existingEntity = _entityFaker.Generate(); + var newEntity = _entityFaker.Generate(); var collection = new List { existingEntity }; // Act @@ -93,11 +96,12 @@ public void AddIfNotExists_WhenEntityDoesNotExist_ShouldAddToNonEmptyCollection( public void AddIfNotExists_WhenMultipleEntitiesExist_ShouldFindExistingByIdOnly() { // Arrange - var targetId = Guid.NewGuid(); - var entity1 = new TestEntity { Id = Guid.NewGuid(), Name = "Entity 1" }; - var entity2 = new TestEntity { Id = targetId, Name = "Entity 2" }; - var entity3 = new TestEntity { Id = Guid.NewGuid(), Name = "Entity 3" }; - var duplicateEntity = new TestEntity { Id = targetId, Name = "Different Name" }; + var faker = new Faker(); + var targetId = faker.Random.Guid(); + var entity1 = _entityFaker.Generate(); + var entity2 = new TestEntity { Id = targetId, Name = faker.Person.FullName }; + var entity3 = _entityFaker.Generate(); + var duplicateEntity = new TestEntity { Id = targetId, Name = faker.Person.FullName }; var collection = new List { entity1, entity2, entity3 }; // Act @@ -109,20 +113,15 @@ public void AddIfNotExists_WhenMultipleEntitiesExist_ShouldFindExistingByIdOnly( collection.Count.ShouldBe(3); collection.Count(e => e.Id == targetId).ShouldBe(1); }); - } [TestMethod] public void AddIfNotExists_WhenEntityWithNewIdAdded_ShouldIncreaseCollectionCount() { // Arrange - var collection = new List - { - new() { Id = Guid.NewGuid(), Name = "Entity 1" }, - new() { Id = Guid.NewGuid(), Name = "Entity 2" } - }; + var collection = new List { _entityFaker.Generate(), _entityFaker.Generate() }; var initialCount = collection.Count; - var newEntity = new TestEntity { Id = Guid.NewGuid(), Name = "Entity 3" }; + var newEntity = _entityFaker.Generate(); // Act newEntity.AddIfNotExists(collection); @@ -139,8 +138,7 @@ public void AddIfNotExists_WhenEntityWithNewIdAdded_ShouldIncreaseCollectionCoun public void AddIfNotExists_WhenMultipleCallsWithSameEntity_ShouldOnlyAddOnce() { // Arrange - var entityId = Guid.NewGuid(); - var entity = new TestEntity { Id = entityId, Name = "Test Entity" }; + var entity = _entityFaker.Generate(); var collection = new List(); // Act @@ -160,7 +158,8 @@ public void AddIfNotExists_WhenMultipleCallsWithSameEntity_ShouldOnlyAddOnce() public void AddIfNotExists_WhenEntityIdIsEmptyGuid_ShouldAddEntity() { // Arrange - var entity = new TestEntity { Id = Guid.Empty, Name = "Entity with Empty ID" }; + var faker = new Faker(); + var entity = new TestEntity { Id = Guid.Empty, Name = faker.Person.FullName }; var collection = new List(); // Act @@ -178,8 +177,9 @@ public void AddIfNotExists_WhenEntityIdIsEmptyGuid_ShouldAddEntity() public void AddIfNotExists_WhenEntityWithEmptyIdAlreadyExists_ShouldNotAddDuplicate() { // Arrange - var existingEntity = new TestEntity { Id = Guid.Empty, Name = "Existing Entity" }; - var newEntity = new TestEntity { Id = Guid.Empty, Name = "New Entity" }; + var faker = new Faker(); + var existingEntity = new TestEntity { Id = Guid.Empty, Name = faker.Person.FullName }; + var newEntity = new TestEntity { Id = Guid.Empty, Name = faker.Person.FullName }; var collection = new List { existingEntity }; // Act @@ -189,7 +189,7 @@ public void AddIfNotExists_WhenEntityWithEmptyIdAlreadyExists_ShouldNotAddDuplic collection.ShouldSatisfyAllConditions(() => { _ = collection.ShouldHaveSingleItem(); - collection[0].Name.ShouldBe("Existing Entity"); + collection[0].Id.ShouldBe(Guid.Empty); }); } @@ -197,18 +197,18 @@ public void AddIfNotExists_WhenEntityWithEmptyIdAlreadyExists_ShouldNotAddDuplic public void AddIfNotExists_WithHashSetCollection_ShouldWorkCorrectly() { // Arrange - var entityId = Guid.NewGuid(); - var entity = new TestEntity { Id = entityId, Name = "Test Entity" }; - var collection = new HashSet([new TestEntity { Id = Guid.NewGuid(), Name = "Existing" }]); + var newEntity = _entityFaker.Generate(); + var existingEntity = _entityFaker.Generate(); + var collection = new HashSet { existingEntity }; // Act - entity.AddIfNotExists(collection); + newEntity.AddIfNotExists(collection); // Assert collection.ShouldSatisfyAllConditions(() => { collection.Count.ShouldBe(2); - collection.ShouldContain(entity); + collection.ShouldContain(newEntity); }); } @@ -216,9 +216,11 @@ public void AddIfNotExists_WithHashSetCollection_ShouldWorkCorrectly() public void AddIfNotExists_WhenPreservingExistingEntityProperties_ShouldNotReplaceExistingEntity() { // Arrange - var entityId = Guid.NewGuid(); - var existingEntity = new TestEntity { Id = entityId, Name = "Original Name" }; - var newEntity = new TestEntity { Id = entityId, Name = "Updated Name" }; + var faker = new Faker(); + var entityId = faker.Random.Guid(); + var existingName = faker.Person.FullName; + var existingEntity = new TestEntity { Id = entityId, Name = existingName }; + var newEntity = new TestEntity { Id = entityId, Name = faker.Person.FullName }; var collection = new List { existingEntity }; // Act @@ -228,9 +230,8 @@ public void AddIfNotExists_WhenPreservingExistingEntityProperties_ShouldNotRepla collection.ShouldSatisfyAllConditions(() => { _ = collection.ShouldHaveSingleItem(); - collection[0].Name.ShouldBe("Original Name"); + collection[0].Name.ShouldBe(existingName); collection[0].ShouldBe(existingEntity); }); } } - diff --git a/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs b/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs index 38c707a..3c3ec43 100644 --- a/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs +++ b/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Domain.Entities; using InvoiceReminder.Domain.Extensions; using Shouldly; @@ -7,12 +8,47 @@ namespace InvoiceReminder.DomainEntities.UnitTests.Extensions; [TestClass] public sealed class UserExtensionsTests { + private readonly Faker _invoiceFaker; + private readonly Faker _jobScheduleFaker; + private readonly Faker _emailAuthTokenFaker; + private readonly Faker _scanEmailDefinitionFaker; + + public UserExtensionsTests() + { + _invoiceFaker = new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()); + + _jobScheduleFaker = new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()); + + _emailAuthTokenFaker = new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()); + + _scanEmailDefinitionFaker = new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()); + } + + private static Faker UserFaker( + ICollection invoices = default, + ICollection jobSchedules = default, + ICollection emailAuthTokens = default, + ICollection scanEmailDefinitions = default) + { + return new Faker() + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.Name, faker => faker.Person.FullName) + .RuleFor(u => u.Invoices, faker => invoices ?? new HashSet()) + .RuleFor(u => u.JobSchedules, faker => jobSchedules ?? new HashSet()) + .RuleFor(u => u.EmailAuthTokens, faker => emailAuthTokens ?? new HashSet()) + .RuleFor(u => u.ScanEmailDefinitions, faker => scanEmailDefinitions ?? new HashSet()); + } + [TestMethod] public void Handle_NewUser_AddsUserToResult() { // Arrange var result = new Dictionary(); - var user = new User { Id = Guid.NewGuid(), Name = "Test User" }; + var user = UserFaker().Generate(); var parameters = new UserParameters(); // Act @@ -39,8 +75,8 @@ public void Handle_NewUserWithInvoice_AddsInvoiceToUserAndResult() { // Arrange var result = new Dictionary(); - var user = new User { Id = Guid.NewGuid(), Name = "Test User" }; - var invoice = new Invoice { Id = Guid.NewGuid() }; + var user = UserFaker().Generate(); + var invoice = _invoiceFaker.Generate(); var parameters = new UserParameters { Invoice = invoice }; // Act @@ -67,8 +103,8 @@ public void Handle_NewUserWithJobSchedule_AddsJobScheduleToUserAndResult() { // Arrange var result = new Dictionary(); - var user = new User { Id = Guid.NewGuid(), Name = "Test User" }; - var jobSchedule = new JobSchedule { Id = Guid.NewGuid() }; + var user = UserFaker().Generate(); + var jobSchedule = _jobScheduleFaker.Generate(); var parameters = new UserParameters { JobSchedule = jobSchedule }; // Act @@ -95,8 +131,8 @@ public void Handle_NewUserWithEmailAuthToken_AddsEmailAuthTokenToUserAndResult() { // Arrange var result = new Dictionary(); - var user = new User { Id = Guid.NewGuid(), Name = "Test User" }; - var emailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; + var user = UserFaker().Generate(); + var emailAuthToken = _emailAuthTokenFaker.Generate(); var parameters = new UserParameters { EmailAuthToken = emailAuthToken }; // Act @@ -123,8 +159,8 @@ public void Handle_NewUserWithScanEmailDefinition_AddsScanEmailDefinitionToUserA { // Arrange var result = new Dictionary(); - var user = new User { Id = Guid.NewGuid(), Name = "Test User" }; - var scanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; + var user = UserFaker().Generate(); + var scanEmailDefinition = _scanEmailDefinitionFaker.Generate(); var parameters = new UserParameters { ScanEmailDefinition = scanEmailDefinition }; // Act @@ -149,20 +185,11 @@ public void Handle_NewUserWithScanEmailDefinition_AddsScanEmailDefinitionToUserA public void Handle_ExistingUserWithNewInvoice_AddsInvoiceToExistingUserInResult() { // Arrange - var userId = Guid.NewGuid(); - var existingInvoice = new Invoice { Id = Guid.NewGuid() }; - var existingUser = new User - { - Id = userId, - Name = "Existing User", - Invoices = [existingInvoice], - JobSchedules = [], - EmailAuthTokens = [], - ScanEmailDefinitions = [] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingInvoice = _invoiceFaker.Generate(); + var existingUser = UserFaker(invoices: [existingInvoice]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; - var newInvoice = new Invoice { Id = Guid.NewGuid() }; + var newInvoice = _invoiceFaker.Generate(); var parameters = new UserParameters { Invoice = newInvoice }; // Act @@ -171,9 +198,9 @@ public void Handle_ExistingUserWithNewInvoice_AddsInvoiceToExistingUserInResult( // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].Invoices.ShouldContain(existingInvoice); - result[userId].Invoices.ShouldContain(newInvoice); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].Invoices.ShouldContain(existingInvoice); + result[existingUser.Id].Invoices.ShouldContain(newInvoice); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -191,20 +218,11 @@ public void Handle_ExistingUserWithNewInvoice_AddsInvoiceToExistingUserInResult( public void Handle_ExistingUserWithNewJobSchedule_AddsJobScheduleToExistingUserInResult() { // Arrange - var userId = Guid.NewGuid(); - var existingJobSchedule = new JobSchedule { Id = Guid.NewGuid() }; - var existingUser = new User - { - Id = userId, - Name = "Existing User", - Invoices = [], - JobSchedules = [existingJobSchedule], - EmailAuthTokens = [], - ScanEmailDefinitions = [] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingJobSchedule = _jobScheduleFaker.Generate(); + var existingUser = UserFaker(jobSchedules: [existingJobSchedule]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; - var newJobSchedule = new JobSchedule { Id = Guid.NewGuid() }; + var newJobSchedule = _jobScheduleFaker.Generate(); var parameters = new UserParameters { JobSchedule = newJobSchedule }; // Act @@ -213,9 +231,9 @@ public void Handle_ExistingUserWithNewJobSchedule_AddsJobScheduleToExistingUserI // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].JobSchedules.ShouldContain(existingJobSchedule); - result[userId].JobSchedules.ShouldContain(newJobSchedule); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].JobSchedules.ShouldContain(existingJobSchedule); + result[existingUser.Id].JobSchedules.ShouldContain(newJobSchedule); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -233,20 +251,11 @@ public void Handle_ExistingUserWithNewJobSchedule_AddsJobScheduleToExistingUserI public void Handle_ExistingUserWithNewEmailAuthToken_AddsEmailAuthTokenToExistingUserInResult() { // Arrange - var userId = Guid.NewGuid(); - var existingEmailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; - var existingUser = new User - { - Id = userId, - Name = "Existing User", - Invoices = [], - JobSchedules = [], - EmailAuthTokens = [existingEmailAuthToken], - ScanEmailDefinitions = [] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingEmailAuthToken = _emailAuthTokenFaker.Generate(); + var existingUser = UserFaker(emailAuthTokens: [existingEmailAuthToken]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; - var newEmailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; + var newEmailAuthToken = _emailAuthTokenFaker.Generate(); var parameters = new UserParameters { EmailAuthToken = newEmailAuthToken }; // Act @@ -255,9 +264,9 @@ public void Handle_ExistingUserWithNewEmailAuthToken_AddsEmailAuthTokenToExistin // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].EmailAuthTokens.ShouldContain(existingEmailAuthToken); - result[userId].EmailAuthTokens.ShouldContain(newEmailAuthToken); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].EmailAuthTokens.ShouldContain(existingEmailAuthToken); + result[existingUser.Id].EmailAuthTokens.ShouldContain(newEmailAuthToken); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -275,20 +284,11 @@ public void Handle_ExistingUserWithNewEmailAuthToken_AddsEmailAuthTokenToExistin public void Handle_ExistingUserWithNewScanEmailDefinition_AddsScanEmailDefinitionToExistingUserInResult() { // Arrange - var userId = Guid.NewGuid(); - var existingScanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; - var existingUser = new User - { - Id = userId, - Name = "Existing User", - Invoices = [], - JobSchedules = [], - EmailAuthTokens = [], - ScanEmailDefinitions = [existingScanEmailDefinition] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); + var existingUser = UserFaker(scanEmailDefinitions: [existingScanEmailDefinition]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; - var newScanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; + var newScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); var parameters = new UserParameters { ScanEmailDefinition = newScanEmailDefinition }; // Act @@ -297,9 +297,9 @@ public void Handle_ExistingUserWithNewScanEmailDefinition_AddsScanEmailDefinitio // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); - result[userId].ScanEmailDefinitions.ShouldContain(newScanEmailDefinition); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); + result[existingUser.Id].ScanEmailDefinitions.ShouldContain(newScanEmailDefinition); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -317,10 +317,9 @@ public void Handle_ExistingUserWithNewScanEmailDefinition_AddsScanEmailDefinitio public void Handle_ExistingUserWithSameInvoice_DoesNotAddDuplicate() { // Arrange - var userId = Guid.NewGuid(); - var existingInvoice = new Invoice { Id = Guid.NewGuid() }; - var existingUser = new User { Id = userId, Name = "Existing User", Invoices = [existingInvoice] }; - var result = new Dictionary { { userId, existingUser } }; + var existingInvoice = _invoiceFaker.Generate(); + var existingUser = UserFaker(invoices: [existingInvoice]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { Invoice = existingInvoice }; @@ -330,9 +329,9 @@ public void Handle_ExistingUserWithSameInvoice_DoesNotAddDuplicate() // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].Invoices.Count.ShouldBe(1); - result[userId].Invoices.ShouldContain(existingInvoice); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].Invoices.Count.ShouldBe(1); + result[existingUser.Id].Invoices.ShouldContain(existingInvoice); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -346,10 +345,9 @@ public void Handle_ExistingUserWithSameInvoice_DoesNotAddDuplicate() public void Handle_ExistingUserWithSameJobSchedule_DoesNotAddDuplicate() { // Arrange - var userId = Guid.NewGuid(); - var existingJobSchedule = new JobSchedule { Id = Guid.NewGuid() }; - var existingUser = new User { Id = userId, Name = "Existing User", JobSchedules = [existingJobSchedule] }; - var result = new Dictionary { { userId, existingUser } }; + var existingJobSchedule = _jobScheduleFaker.Generate(); + var existingUser = UserFaker(jobSchedules: [existingJobSchedule]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { JobSchedule = existingJobSchedule }; @@ -359,9 +357,9 @@ public void Handle_ExistingUserWithSameJobSchedule_DoesNotAddDuplicate() // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].JobSchedules.Count.ShouldBe(1); - result[userId].JobSchedules.ShouldContain(existingJobSchedule); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].JobSchedules.Count.ShouldBe(1); + result[existingUser.Id].JobSchedules.ShouldContain(existingJobSchedule); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -375,10 +373,9 @@ public void Handle_ExistingUserWithSameJobSchedule_DoesNotAddDuplicate() public void Handle_ExistingUserWithSameEmailAuthToken_DoesNotAddDuplicate() { // Arrange - var userId = Guid.NewGuid(); - var existingEmailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; - var existingUser = new User { Id = userId, Name = "Existing User", EmailAuthTokens = [existingEmailAuthToken] }; - var result = new Dictionary { { userId, existingUser } }; + var existingEmailAuthToken = _emailAuthTokenFaker.Generate(); + var existingUser = UserFaker(emailAuthTokens: [existingEmailAuthToken]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { EmailAuthToken = existingEmailAuthToken }; @@ -388,9 +385,9 @@ public void Handle_ExistingUserWithSameEmailAuthToken_DoesNotAddDuplicate() // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].EmailAuthTokens.Count.ShouldBe(1); - result[userId].EmailAuthTokens.ShouldContain(existingEmailAuthToken); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].EmailAuthTokens.Count.ShouldBe(1); + result[existingUser.Id].EmailAuthTokens.ShouldContain(existingEmailAuthToken); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -404,15 +401,9 @@ public void Handle_ExistingUserWithSameEmailAuthToken_DoesNotAddDuplicate() public void Handle_ExistingUserWithSameScanEmailDefinition_DoesNotAddDuplicate() { // Arrange - var userId = Guid.NewGuid(); - var existingScanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; - var existingUser = new User - { - Id = userId, - Name = "Existing User", - ScanEmailDefinitions = [existingScanEmailDefinition] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); + var existingUser = UserFaker(scanEmailDefinitions: [existingScanEmailDefinition]).Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { ScanEmailDefinition = existingScanEmailDefinition }; @@ -422,9 +413,9 @@ public void Handle_ExistingUserWithSameScanEmailDefinition_DoesNotAddDuplicate() // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].ScanEmailDefinitions.Count.ShouldBe(1); - result[userId].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].ScanEmailDefinitions.Count.ShouldBe(1); + result[existingUser.Id].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -439,15 +430,11 @@ public void Handle_NewUserWithEmptyCollections_InitializesCollections() { // Arrange var result = new Dictionary(); - var user = new User - { - Id = Guid.NewGuid(), - Name = "Test User" - }; - var invoice = new Invoice { Id = Guid.NewGuid() }; - var jobSchedule = new JobSchedule { Id = Guid.NewGuid() }; - var scanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; - var emailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; + var user = UserFaker().Generate(); + var invoice = _invoiceFaker.Generate(); + var jobSchedule = _jobScheduleFaker.Generate(); + var scanEmailDefinition = _scanEmailDefinitionFaker.Generate(); + var emailAuthToken = _emailAuthTokenFaker.Generate(); var parameters = new UserParameters { Invoice = invoice, @@ -486,22 +473,13 @@ public void Handle_NewUserWithEmptyCollections_InitializesCollections() public void Handle_ExistingUserWithNullCollections_AddsNewItems() { // Arrange - var userId = Guid.NewGuid(); - var existingUser = new User - { - Id = userId, - Name = "Existing User", - Invoices = [], - JobSchedules = [], - EmailAuthTokens = [], - ScanEmailDefinitions = [] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingUser = UserFaker().Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; - var invoice = new Invoice { Id = Guid.NewGuid() }; - var jobSchedule = new JobSchedule { Id = Guid.NewGuid() }; - var emailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; - var scanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; + var invoice = _invoiceFaker.Generate(); + var jobSchedule = _jobScheduleFaker.Generate(); + var scanEmailDefinition = _scanEmailDefinitionFaker.Generate(); + var emailAuthToken = _emailAuthTokenFaker.Generate(); var parameters = new UserParameters { Invoice = invoice, @@ -516,15 +494,15 @@ public void Handle_ExistingUserWithNullCollections_AddsNewItems() // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].Invoices.Count.ShouldBe(1); - result[userId].JobSchedules.Count.ShouldBe(1); - result[userId].EmailAuthTokens.Count.ShouldBe(1); - result[userId].ScanEmailDefinitions.Count.ShouldBe(1); - result[userId].Invoices.ShouldContain(invoice); - result[userId].JobSchedules.ShouldContain(jobSchedule); - result[userId].EmailAuthTokens.ShouldContain(emailAuthToken); - result[userId].ScanEmailDefinitions.ShouldContain(scanEmailDefinition); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].Invoices.Count.ShouldBe(1); + result[existingUser.Id].JobSchedules.Count.ShouldBe(1); + result[existingUser.Id].EmailAuthTokens.Count.ShouldBe(1); + result[existingUser.Id].ScanEmailDefinitions.Count.ShouldBe(1); + result[existingUser.Id].Invoices.ShouldContain(invoice); + result[existingUser.Id].JobSchedules.ShouldContain(jobSchedule); + result[existingUser.Id].EmailAuthTokens.ShouldContain(emailAuthToken); + result[existingUser.Id].ScanEmailDefinitions.ShouldContain(scanEmailDefinition); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -544,21 +522,17 @@ public void Handle_ExistingUserWithNullCollections_AddsNewItems() public void Handle_ExistingUserWithNullParameters_DoesNotModifyUser() { // Arrange - var userId = Guid.NewGuid(); - var existingInvoice = new Invoice { Id = Guid.NewGuid() }; - var existingJobSchedule = new JobSchedule { Id = Guid.NewGuid() }; - var exitingEmailAuthToken = new EmailAuthToken { Id = Guid.NewGuid() }; - var existingScanEmailDefinition = new ScanEmailDefinition { Id = Guid.NewGuid() }; - var existingUser = new User - { - Id = userId, - Name = "Existing User", - Invoices = [existingInvoice], - JobSchedules = [existingJobSchedule], - EmailAuthTokens = [exitingEmailAuthToken], - ScanEmailDefinitions = [existingScanEmailDefinition] - }; - var result = new Dictionary { { userId, existingUser } }; + var existingInvoice = _invoiceFaker.Generate(); + var existingJobSchedule = _jobScheduleFaker.Generate(); + var exitingEmailAuthToken = _emailAuthTokenFaker.Generate(); + var existingScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); + var existingUser = UserFaker( + invoices: [existingInvoice], + jobSchedules: [existingJobSchedule], + emailAuthTokens: [exitingEmailAuthToken], + scanEmailDefinitions: [existingScanEmailDefinition]) + .Generate(); + var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { @@ -574,15 +548,15 @@ public void Handle_ExistingUserWithNullParameters_DoesNotModifyUser() // Assert result.ShouldSatisfyAllConditions(result => { - result.ShouldContainKey(userId); - result[userId].Invoices.ShouldContain(existingInvoice); - result[userId].JobSchedules.ShouldContain(existingJobSchedule); - result[userId].EmailAuthTokens.ShouldContain(exitingEmailAuthToken); - result[userId].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); - result[userId].Invoices.Count.ShouldBe(1); - result[userId].JobSchedules.Count.ShouldBe(1); - result[userId].EmailAuthTokens.Count.ShouldBe(1); - result[userId].ScanEmailDefinitions.Count.ShouldBe(1); + result.ShouldContainKey(existingUser.Id); + result[existingUser.Id].Invoices.ShouldContain(existingInvoice); + result[existingUser.Id].JobSchedules.ShouldContain(existingJobSchedule); + result[existingUser.Id].EmailAuthTokens.ShouldContain(exitingEmailAuthToken); + result[existingUser.Id].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); + result[existingUser.Id].Invoices.Count.ShouldBe(1); + result[existingUser.Id].JobSchedules.Count.ShouldBe(1); + result[existingUser.Id].EmailAuthTokens.Count.ShouldBe(1); + result[existingUser.Id].ScanEmailDefinitions.Count.ShouldBe(1); }); newUserReference.ShouldSatisfyAllConditions(newUserReference => @@ -603,7 +577,7 @@ public void Handle_NewUserWithNullParameters_AddsUserWithEmptyCollections() { // Arrange var result = new Dictionary(); - var user = new User { Id = Guid.NewGuid(), Name = "Test User" }; + var user = UserFaker().Generate(); var parameters = new UserParameters { Invoice = null, diff --git a/InvoiceReminder.DomainEntities.UnitTests/InvoiceReminder.DomainEntities.UnitTests.csproj b/InvoiceReminder.DomainEntities.UnitTests/InvoiceReminder.DomainEntities.UnitTests.csproj index 2c50dd8..ccd4db7 100644 --- a/InvoiceReminder.DomainEntities.UnitTests/InvoiceReminder.DomainEntities.UnitTests.csproj +++ b/InvoiceReminder.DomainEntities.UnitTests/InvoiceReminder.DomainEntities.UnitTests.csproj @@ -16,6 +16,7 @@ + diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs index 8b14a05..4ea886e 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Data.Repository; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; @@ -12,6 +13,7 @@ public sealed class BaseRepositoryTests { private readonly SqliteConnection _connection; private readonly DbContextOptions _contextOptions; + private Faker _testEntityFaker; public TestContext TestContext { get; set; } @@ -28,6 +30,7 @@ public BaseRepositoryTests() [TestInitialize] public async Task Setup() { + InitializeFaker(); using var context = new TestDbContext(_contextOptions); _ = await context.Database.EnsureCreatedAsync(TestContext.CancellationToken); } @@ -38,6 +41,13 @@ public void TearDown() _connection.Dispose(); } + private void InitializeFaker() + { + _testEntityFaker = new Faker() + .RuleFor(e => e.Id, _ => Guid.NewGuid()) + .RuleFor(e => e.Name, f => f.Lorem.Word()); + } + private TestDbContext CreateContext() { return new(_contextOptions); @@ -47,7 +57,7 @@ private TestDbContext CreateContext() public async Task AddAsync_Should_AddEntityToDatabase() { // Arrange - var entity = new TestEntity { Id = Guid.NewGuid(), Name = "Test" }; + var entity = _testEntityFaker.Generate(); using var context = CreateContext(); var repository = new BaseRepository(context); @@ -64,11 +74,7 @@ public async Task AddAsync_Should_AddEntityToDatabase() public async Task BulkInsertAsync_Should_AddMultipleEntitiesToDatabaseWithTimestamps() { // Arrange - var entities = new List - { - new() { Id = Guid.NewGuid(), Name = "Test1" }, - new() { Id = Guid.NewGuid(), Name = "Test2" } - }; + var entities = _testEntityFaker.Generate(2); using var context = CreateContext(); var repository = new BaseRepository(context); @@ -86,20 +92,18 @@ public async Task BulkInsertAsync_Should_AddMultipleEntitiesToDatabaseWithTimest total.ShouldBe(entities.Count); context.TestEntities.ShouldAllBe(e => e.CreatedAt.HasValue && e.UpdatedAt.HasValue); }); - } [TestMethod] public async Task Remove_Should_RemoveExistingEntityFromDatabase() { // Arrange - var entity = new TestEntity { Id = Guid.NewGuid(), Name = "Test" }; + var entity = _testEntityFaker.Generate(); using var context = CreateContext(); var repository = new BaseRepository(context); _ = await repository.AddAsync(entity, TestContext.CancellationToken); _ = await context.SaveChangesAsync(TestContext.CancellationToken); - // Act repository.Remove(entity); _ = await context.SaveChangesAsync(TestContext.CancellationToken); @@ -112,7 +116,7 @@ public async Task Remove_Should_RemoveExistingEntityFromDatabase() public async Task Remove_Should_AttachAndRemoveDetachedEntity() { // Arrange - var entity = new TestEntity { Id = Guid.NewGuid(), Name = "Test" }; + var entity = _testEntityFaker.Generate(); using var context = CreateContext(); var repository = new BaseRepository(context); @@ -134,7 +138,7 @@ public async Task Remove_Should_AttachAndRemoveDetachedEntity() public async Task GetByIdAsync_Should_ReturnEntityById() { // Arrange - var entity = new TestEntity { Id = Guid.NewGuid(), Name = "Test" }; + var entity = _testEntityFaker.Generate(); using var context = CreateContext(); var repository = new BaseRepository(context); @@ -172,11 +176,7 @@ public async Task GetByIdAsync_Should_ReturnNullWhenEntityNotFound() public async Task GetAll_Should_ReturnAllEntities() { // Arrange - var entities = new List - { - new() { Id = Guid.NewGuid(), Name = "Test1" }, - new() { Id = Guid.NewGuid(), Name = "Test2" } - }; + var entities = _testEntityFaker.Generate(2); using var context = CreateContext(); var repository = new BaseRepository(context); @@ -200,14 +200,15 @@ public async Task GetAll_Should_ReturnAllEntities() public async Task Update_Should_UpdateExistingEntity() { // Arrange - var entity = new TestEntity { Id = Guid.NewGuid(), Name = "Original Name" }; + var entity = _testEntityFaker.Generate(); using var context = CreateContext(); var repository = new BaseRepository(context); _ = await repository.AddAsync(entity, TestContext.CancellationToken); _ = await context.SaveChangesAsync(TestContext.CancellationToken); - entity.Name = "Updated Name"; + var updatedName = new Faker().Lorem.Word(); + entity.Name = updatedName; // Act var updatedEntity = repository.Update(entity); @@ -220,7 +221,7 @@ public async Task Update_Should_UpdateExistingEntity() retrievedEntity.ShouldSatisfyAllConditions(() => { _ = retrievedEntity.ShouldNotBeNull(); - retrievedEntity.Name.ShouldBe("Updated Name"); + retrievedEntity.Name.ShouldBe(updatedName); }); } @@ -228,7 +229,7 @@ public async Task Update_Should_UpdateExistingEntity() public async Task Update_Should_AttachAndUpdateDetachedEntity() { // Arrange - var entity = new TestEntity { Id = Guid.NewGuid(), Name = "Original Name" }; + var entity = _testEntityFaker.Generate(); using var context = CreateContext(); var repository = new BaseRepository(context); @@ -238,7 +239,8 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() _ = context.Attach(entity); context.Entry(entity).State = EntityState.Detached; - entity.Name = "Updated Name"; + var updatedName = new Faker().Lorem.Word(); + entity.Name = updatedName; // Act var updatedEntity = repository.Update(entity); @@ -251,7 +253,7 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() retrievedEntity.ShouldSatisfyAllConditions(() => { _ = retrievedEntity.ShouldNotBeNull(); - retrievedEntity.Name.ShouldBe("Updated Name"); + retrievedEntity.Name.ShouldBe(updatedName); }); } @@ -261,9 +263,9 @@ public async Task Where_Should_ReturnEntitiesMatchingPredicate() // Arrange var entities = new List { - new() { Id = Guid.NewGuid(), Name = "Test1" }, - new() { Id = Guid.NewGuid(), Name = "AnotherTest" }, - new() { Id = Guid.NewGuid(), Name = "Test2" } + _testEntityFaker.RuleFor(e => e.Name, _ => "Test1").Generate(), + _testEntityFaker.RuleFor(e => e.Name, _ => "AnotherTest").Generate(), + _testEntityFaker.RuleFor(e => e.Name, _ => "Test2").Generate() }; using var context = CreateContext(); diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs index b7b09fa..71fc625 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs @@ -1,7 +1,9 @@ +using Bogus; using InvoiceReminder.Data.Interfaces; using InvoiceReminder.Data.Persistence; using InvoiceReminder.Data.Repository; using InvoiceReminder.Domain.Entities; +using InvoiceReminder.Domain.Enums; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using NSubstitute; @@ -15,6 +17,7 @@ public sealed class ScanEmailDefinitionRepositoryTests private readonly CoreDbContext _dbContext; private readonly ILogger _logger; private readonly IScanEmailDefinitionRepository _repository; + private Faker _scanEmailDefinitionFaker; public TestContext TestContext { get; set; } @@ -29,6 +32,24 @@ public ScanEmailDefinitionRepositoryTests() _repository = Substitute.For(); } + [TestInitialize] + public void Setup() + { + InitializeFaker(); + } + + private void InitializeFaker() + { + _scanEmailDefinitionFaker = new Faker() + .RuleFor(s => s.Id, _ => Guid.NewGuid()) + .RuleFor(s => s.UserId, _ => Guid.NewGuid()) + .RuleFor(s => s.InvoiceType, f => f.PickRandom()) + .RuleFor(s => s.Beneficiary, f => f.Company.CompanyName()) + .RuleFor(s => s.Description, f => f.Lorem.Sentence()) + .RuleFor(s => s.SenderEmailAddress, f => f.Internet.Email()) + .RuleFor(s => s.AttachmentFileName, f => f.System.FileName()); + } + [TestMethod] public void ScanEmailDefinitionRepository_ShouldBeAssignableToItsInterface_And_GenericInterface_And_GenericRepository() { @@ -52,13 +73,17 @@ public async Task GetBySenderBeneficiaryAsync_ShouldReturnScanEmailDefinition_Wh { // Arrange var userId = Guid.NewGuid(); - var scanEmailDefinition = new ScanEmailDefinition { UserId = userId, Beneficiary = "test" }; + var beneficiary = new Faker().Company.CompanyName(); + var scanEmailDefinition = _scanEmailDefinitionFaker + .RuleFor(s => s.UserId, _ => userId) + .RuleFor(s => s.Beneficiary, _ => beneficiary) + .Generate(); _ = _repository.GetBySenderBeneficiaryAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(Task.FromResult(scanEmailDefinition)); // Act - var result = await _repository.GetBySenderBeneficiaryAsync("test", userId, TestContext.CancellationToken); + var result = await _repository.GetBySenderBeneficiaryAsync(beneficiary, userId, TestContext.CancellationToken); // Assert result.ShouldSatisfyAllConditions(() => @@ -66,6 +91,7 @@ public async Task GetBySenderBeneficiaryAsync_ShouldReturnScanEmailDefinition_Wh _ = result.ShouldNotBeNull(); _ = result.ShouldBeOfType(); result.UserId.ShouldBe(userId); + result.Beneficiary.ShouldBe(beneficiary); }); } @@ -74,13 +100,17 @@ public async Task GetBySenderEmailAsync_ShouldReturnScanEmailDefinition_WhenScan { // Arrange var userId = Guid.NewGuid(); - var scanEmailDefinition = new ScanEmailDefinition { UserId = userId, SenderEmailAddress = "test@mail.com" }; + var senderEmail = new Faker().Internet.Email(); + var scanEmailDefinition = _scanEmailDefinitionFaker + .RuleFor(s => s.UserId, _ => userId) + .RuleFor(s => s.SenderEmailAddress, _ => senderEmail) + .Generate(); _ = _repository.GetBySenderEmailAddressAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(Task.FromResult(scanEmailDefinition)); // Act - var result = await _repository.GetBySenderEmailAddressAsync("test@mail.com", userId, TestContext.CancellationToken); + var result = await _repository.GetBySenderEmailAddressAsync(senderEmail, userId, TestContext.CancellationToken); // Assert result.ShouldSatisfyAllConditions(() => @@ -88,6 +118,7 @@ public async Task GetBySenderEmailAsync_ShouldReturnScanEmailDefinition_WhenScan _ = result.ShouldNotBeNull(); _ = result.ShouldBeOfType(); result.UserId.ShouldBe(userId); + result.SenderEmailAddress.ShouldBe(senderEmail); }); } @@ -96,11 +127,9 @@ public async Task GetByUserIdAsync_ShouldReturnScanEmailDefinition_WhenScanEmail { // Arrange var userId = Guid.NewGuid(); - var collection = new List - { - new() { Id = Guid.NewGuid(), UserId = userId, Beneficiary = "test_A" }, - new() { Id = Guid.NewGuid(), UserId = userId, Beneficiary = "test_B" } - }; + var collection = _scanEmailDefinitionFaker + .RuleFor(s => s.UserId, _ => userId) + .Generate(2); _ = _repository.GetByUserIdAsync(Arg.Any(), Arg.Any()) .Returns(Task.FromResult>(collection)); @@ -115,6 +144,7 @@ public async Task GetByUserIdAsync_ShouldReturnScanEmailDefinition_WhenScanEmail _ = result.ShouldBeOfType>(); result.ShouldNotBeEmpty(); result.ShouldContain(x => x.UserId == userId); + result.Count().ShouldBe(2); }); } } diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs index 8a1037f..988ebf7 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Data.Interfaces; using InvoiceReminder.Data.Persistence; using InvoiceReminder.Data.Repository; @@ -15,6 +16,7 @@ public sealed class UserRepositoryTests private readonly CoreDbContext _dbContext; private readonly ILogger _logger; private readonly IUserRepository _repository; + private Faker _userFaker; public TestContext TestContext { get; set; } @@ -29,6 +31,22 @@ public UserRepositoryTests() _repository = Substitute.For(); } + [TestInitialize] + public void Setup() + { + InitializeFaker(); + } + + private void InitializeFaker() + { + _userFaker = new Faker() + .RuleFor(u => u.Id, _ => Guid.NewGuid()) + .RuleFor(u => u.TelegramChatId, f => f.Random.Long(100000000, long.MaxValue)) + .RuleFor(u => u.Name, f => f.Person.FullName) + .RuleFor(u => u.Email, f => f.Internet.Email()) + .RuleFor(u => u.Password, f => f.Internet.Password(length: 16, memorable: false)); + } + [TestMethod] public void UserRepository_ShouldBeAssignableToItsInterface_And_GenericInterface_And_GenericRepository() { @@ -51,8 +69,10 @@ public void UserRepository_ShouldBeAssignableToItsInterface_And_GenericInterface public async Task GetByEmailAsync_ShouldReturnUser_WhenUserExists() { // Arrange - var email = "user_test@mail.com"; - var user = new User { Id = Guid.NewGuid(), Email = email }; + var email = new Faker().Internet.Email(); + var user = _userFaker + .RuleFor(u => u.Email, _ => email) + .Generate(); _ = _repository.GetByEmailAsync(Arg.Any(), Arg.Any()) .Returns(Task.FromResult(user)); @@ -66,6 +86,7 @@ public async Task GetByEmailAsync_ShouldReturnUser_WhenUserExists() _ = result.ShouldNotBeNull(); _ = result.ShouldBeOfType(); result.Email.ShouldBe(email); + result.Id.ShouldNotBe(Guid.Empty); }); } @@ -74,7 +95,9 @@ public async Task GetByIdAsync_ShouldReturnUser_WhenUserExists() { // Arrange var userId = Guid.NewGuid(); - var user = new User { Id = userId }; + var user = _userFaker + .RuleFor(u => u.Id, _ => userId) + .Generate(); _ = _repository.GetByIdAsync(Arg.Any(), Arg.Any()) .Returns(Task.FromResult(user)); diff --git a/InvoiceReminder.Infrastructure.UnitTests/InvoiceReminder.Infrastructure.UnitTests.csproj b/InvoiceReminder.Infrastructure.UnitTests/InvoiceReminder.Infrastructure.UnitTests.csproj index 4ef0b10..1f094f2 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/InvoiceReminder.Infrastructure.UnitTests.csproj +++ b/InvoiceReminder.Infrastructure.UnitTests/InvoiceReminder.Infrastructure.UnitTests.csproj @@ -17,6 +17,7 @@ + diff --git a/InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs b/InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs index 6655524..20b4882 100644 --- a/InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs +++ b/InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs @@ -1,3 +1,4 @@ +using Bogus; using InvoiceReminder.Domain.Entities; using InvoiceReminder.JobScheduler.HostedService; using Microsoft.Extensions.Logging; @@ -17,6 +18,7 @@ public sealed class QuartzHostedServiceTests private readonly IScheduler _scheduler; private readonly List _schedules; private readonly QuartzHostedService _service; + private Faker _jobScheduleFaker; public TestContext TestContext { get; set; } @@ -26,24 +28,33 @@ public QuartzHostedServiceTests() _schedulerFactory = Substitute.For(); _jobFactory = Substitute.For(); _scheduler = Substitute.For(); - _schedules = - [ - new() { - Id = Guid.NewGuid(), - UserId = Guid.NewGuid(), - CronExpression = "0/5 * * * * ?" - } - ]; + _schedules = []; _service = Substitute.For(_logger, _schedulerFactory, _jobFactory, _schedules); _ = _schedulerFactory.GetScheduler(Arg.Any()).Returns(Task.FromResult(_scheduler)); } + [TestInitialize] + public void Setup() + { + InitializeFaker(); + _schedules.Clear(); + } + + private void InitializeFaker() + { + _jobScheduleFaker = new Faker() + .RuleFor(j => j.Id, _ => Guid.NewGuid()) + .RuleFor(j => j.UserId, _ => Guid.NewGuid()) + .RuleFor(j => j.CronExpression, _ => "0/5 * * * * ?"); + } + [TestMethod] public async Task ScheduleJobAsync_ShouldScheduleJobAndStartScheduler() { // Arrange - var schedule = _schedules[0]; + var schedule = _jobScheduleFaker.Generate(); + _schedules.Add(schedule); // Act await _service.ScheduleJobAsync(schedule, TestContext.CancellationToken); @@ -73,7 +84,8 @@ await _service.ScheduleJobAsync(null, TestContext.CancellationToken) public async Task DeleteJobAsync_ShouldDeleteJobIfExists() { // Arrange - var schedule = _schedules[0]; + var schedule = _jobScheduleFaker.Generate(); + _schedules.Add(schedule); var jobKey = new JobKey($"{schedule.Id}.job"); _ = _scheduler.CheckExists(jobKey, Arg.Is(ct => ct == TestContext.CancellationToken)) @@ -103,7 +115,8 @@ await _service.DeleteJobAsync(null, TestContext.CancellationToken) public async Task PauseJobAsync_ShouldPauseTriggerAndJob() { // Arrange - var schedule = _schedules[0]; + var schedule = _jobScheduleFaker.Generate(); + _schedules.Add(schedule); // Act await _service.PauseJobAsync(schedule, TestContext.CancellationToken); @@ -131,7 +144,8 @@ await _service.PauseJobAsync(null, TestContext.CancellationToken) public async Task ResumeJobAsync_ShouldResumeTriggerAndJob() { // Arrange - var schedule = new JobSchedule { Id = Guid.NewGuid() }; + var schedule = _jobScheduleFaker.Generate(); + _schedules.Add(schedule); var service = new QuartzHostedService(_logger, _schedulerFactory, _jobFactory, _schedules); // Act @@ -162,7 +176,10 @@ await service.ResumeJobAsync(null, TestContext.CancellationToken) [TestMethod] public async Task StartAsync_ShouldScheduleAndStartAllSchedules() { - // Arrange & Act + // Arrange + _schedules.Add(_jobScheduleFaker.Generate()); + + // Act await _service.StartAsync(TestContext.CancellationToken); // Assert @@ -180,9 +197,12 @@ public async Task StartAsync_ShouldScheduleAndStartAllSchedules() public async Task StartAsync_InvalidCronExpression_ShouldLogError() { // Arrange - var schedule = new JobSchedule { Id = Guid.NewGuid(), CronExpression = "invalid cron", UserId = Guid.NewGuid() }; - var schedules = new List { schedule }; - var service = new QuartzHostedService(_logger, _schedulerFactory, _jobFactory, schedules); + var schedule = _jobScheduleFaker + .RuleFor(j => j.CronExpression, _ => "invalid cron") + .Generate(); + + _schedules.Add(schedule); + var service = new QuartzHostedService(_logger, _schedulerFactory, _jobFactory, _schedules); _ = _logger.IsEnabled(Arg.Any()).Returns(true); @@ -204,7 +224,10 @@ public async Task StartAsync_InvalidCronExpression_ShouldLogError() [TestMethod] public async Task StopAsync_ShouldShutdownScheduler() { - // Arrange & Act + // Arrange + _schedules.Add(_jobScheduleFaker.Generate()); + + // Act await _service.StartAsync(TestContext.CancellationToken); await _service.StopAsync(TestContext.CancellationToken); diff --git a/InvoiceReminder.JobScheduler.UnitTests/InvoiceReminder.JobScheduler.UnitTests.csproj b/InvoiceReminder.JobScheduler.UnitTests/InvoiceReminder.JobScheduler.UnitTests.csproj index 618eb11..a4e37a0 100644 --- a/InvoiceReminder.JobScheduler.UnitTests/InvoiceReminder.JobScheduler.UnitTests.csproj +++ b/InvoiceReminder.JobScheduler.UnitTests/InvoiceReminder.JobScheduler.UnitTests.csproj @@ -15,6 +15,7 @@ + all diff --git a/InvoiceReminder.sln b/InvoiceReminder.sln index 6997efe..a69510d 100644 --- a/InvoiceReminder.sln +++ b/InvoiceReminder.sln @@ -65,6 +65,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Itens de Solução", "Itens Directory.Build.props = Directory.Build.props Directory.Packages.props = Directory.Packages.props docker-compose.yml = docker-compose.yml + global.json = global.json EndProjectSection EndProject Global diff --git a/global.json b/global.json new file mode 100644 index 0000000..12d1731 --- /dev/null +++ b/global.json @@ -0,0 +1,9 @@ +{ + "sdk": { + "version": "10.0.100" + }, + + "test": { + "runner": "Microsoft.Testing.Platform" + } +} From eb915034c7e8e350d4b2ac099f42023e5c80669f Mon Sep 17 00:00:00 2001 From: "Jefferson L. da Silva" Date: Fri, 19 Dec 2025 10:42:54 -0300 Subject: [PATCH 2/5] Refactoring based on code review --- .github/workflows/workflow-ci.yml | 8 ++ .../Endpoints/InvoiceEndpointsTests.cs | 4 +- .../Endpoints/InvoiceEndpoints.cs | 2 + .../Endpoints/ScanEmailDefinitionEndpoints.cs | 3 + .../Endpoints/SendMessageEndpoints.cs | 6 +- .../Endpoints/UserEndpoints.cs | 4 +- .../AppServices/BaseAppServiceTests.cs | 16 +++- .../AppServices/JobScheduleAppServiceTests.cs | 32 ++++--- .../AppServices/UserAppServiceTests.cs | 15 ++-- .../Extensions/UserExtensionsTests.cs | 84 ++++++++++++------- .../Data/Repository/BaseRepositoryTests.cs | 4 +- .../ScanEmailDefinitionRepositoryTests.cs | 21 ++--- .../Data/Repository/UserRepositoryTests.cs | 15 +--- 13 files changed, 128 insertions(+), 86 deletions(-) diff --git a/.github/workflows/workflow-ci.yml b/.github/workflows/workflow-ci.yml index 8fc162f..4a8cea5 100644 --- a/.github/workflows/workflow-ci.yml +++ b/.github/workflows/workflow-ci.yml @@ -22,6 +22,14 @@ jobs: with: dotnet-version: 10.0.x + - name: Set UTF-8 locale + run: | + sudo apt-get update + sudo apt-get install -y locales + sudo locale-gen en_US.UTF-8 + export LANG=en_US.UTF-8 + export LC_ALL=en_US.UTF-8 + - name: Restore dependencies run: dotnet restore diff --git a/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs b/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs index a42133d..d258d3c 100644 --- a/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs +++ b/InvoiceReminder.API.UnitTests/Endpoints/InvoiceEndpointsTests.cs @@ -142,7 +142,7 @@ public async Task GetInvoiceById_WhenUserIsAuthenticated_ShouldReturnOk() request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); var expectedResult = Result.Success( - _invoiceViewModelFaker.RuleFor(i => i.Id, id).Generate()); + _invoiceViewModelFaker.Clone().RuleFor(i => i.Id, id).Generate()); _ = _invoiceAppService.GetByIdAsync(Arg.Any(), Arg.Any()).Returns(expectedResult); @@ -271,7 +271,7 @@ public async Task GetInvoiceByBarcode_WhenUserIsAuthenticated_ShouldReturnOk() request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "test_token"); var expectedResult = Result.Success( - _invoiceViewModelFaker.RuleFor(i => i.Barcode, barcode).Generate()); + _invoiceViewModelFaker.Clone().RuleFor(i => i.Barcode, barcode).Generate()); _ = _invoiceAppService.GetByBarcodeAsync(Arg.Any(), Arg.Any()) .Returns(expectedResult); diff --git a/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs b/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs index a4c3957..5ef59a6 100644 --- a/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/InvoiceEndpoints.cs @@ -51,6 +51,7 @@ private static void MapGetInvoice(RouteGroupBuilder endpoint) .RequireAuthorization() .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); } @@ -69,6 +70,7 @@ private static void MapGetInvoiceByBarcode(RouteGroupBuilder endpoint) .RequireAuthorization() .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); } diff --git a/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs b/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs index e305be5..b84c469 100644 --- a/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/ScanEmailDefinitionEndpoints.cs @@ -53,6 +53,7 @@ private static void MapGetScanEmailDefinition(RouteGroupBuilder endpoint) .RequireAuthorization() .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); } @@ -71,6 +72,7 @@ private static void MapGetByUserId(RouteGroupBuilder endpoint) .RequireAuthorization() .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); } @@ -92,6 +94,7 @@ private static void MapGetBySenderEmailAddress(RouteGroupBuilder endpoint) .RequireAuthorization() .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status400BadRequest) + .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status500InternalServerError); } diff --git a/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs b/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs index 7cb692a..61e8004 100644 --- a/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/SendMessageEndpoints.cs @@ -22,7 +22,11 @@ private static void MapSendMessage(RouteGroupBuilder endpoint) return !string.IsNullOrEmpty(result) ? Results.Ok(result) - : Results.Problem(result); + : Results.Problem( + statusCode: StatusCodes.Status500InternalServerError, + title: "Erro ao enviar mensagem", + detail: "O serviço não retornou um resultado válido." + ); }) .WithName("SendMessage") .RequireAuthorization() diff --git a/InvoiceReminder.API/Endpoints/UserEndpoints.cs b/InvoiceReminder.API/Endpoints/UserEndpoints.cs index 1981c9c..eacb5b4 100644 --- a/InvoiceReminder.API/Endpoints/UserEndpoints.cs +++ b/InvoiceReminder.API/Endpoints/UserEndpoints.cs @@ -84,7 +84,7 @@ private static void MapCreateUser(RouteGroupBuilder endpoint) var result = await userAppService.AddAsync(userViewModel, ct); return result.IsSuccess - ? Results.Created($"{basepath}/{result.Value.Email}", result.Value) + ? Results.Created($"{basepath}/{result.Value.Id}", result.Value) : Results.Problem(result.Error); }) .WithName("CreateUser") @@ -107,7 +107,7 @@ private static void MapCreateUsers(RouteGroupBuilder endpoint) var result = await userAppService.BulkInsertAsync(usersViewModel, ct); return result.IsSuccess - ? Results.Created($"{basepath}/", result.Value) + ? Results.Created($"{basepath}", result.Value) : Results.Problem(result.Error); }) .WithName("CreateUsers") diff --git a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs index 627bcf4..a425f67 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs @@ -26,10 +26,16 @@ public BaseAppServiceTests() _appService = new BaseAppService(_repository, _unitOfWork); _entityFaker = new Faker() - .RuleFor(e => e.Name, faker => faker.Person.FullName); + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.Name, faker => faker.Person.FullName) + .RuleFor(e => e.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(e => e.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); _entityViewModelFaker = new Faker() - .RuleFor(e => e.Name, faker => faker.Person.FullName); + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.Name, faker => faker.Person.FullName) + .RuleFor(e => e.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) + .RuleFor(e => e.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } [TestMethod] @@ -278,10 +284,16 @@ public async Task UpdateAsync_Should_Return_Failure_When_ViewModel_Is_Null() public sealed class TestEntity { + public Guid Id { get; set; } public string Name { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } } public sealed class TestEntityViewModel { + public Guid Id { get; set; } public string Name { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } } diff --git a/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs index 83c8c47..9001ce8 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs @@ -19,6 +19,7 @@ public sealed class JobScheduleAppServiceTests private readonly IJobFactory _jobFactory; private readonly ISchedulerFactory _schedulerFactory; private readonly Faker _faker; + private readonly string[] _validCronExpressions; public TestContext TestContext { get; set; } @@ -29,38 +30,33 @@ public JobScheduleAppServiceTests() _jobFactory = Substitute.For(); _schedulerFactory = Substitute.For(); _faker = new Faker(); + _validCronExpressions = [ + "0 0/5 * * * ?",// Every 5 minutes + "0 0 * * * ?", // Every hour + "0 0 0 * * ?", // Every day at midnight + "0 0 0 ? * MON",// Every Monday + "0 0 0 1 * ?", // First day of month + "0 0 0 1 1 ?", // Every January 1st + "0 0 12 * * ?" // Every noon + ]; } - private static Faker CreateJobScheduleFaker() + private Faker CreateJobScheduleFaker() { return new Faker() .RuleFor(j => j.Id, faker => faker.Random.Guid()) .RuleFor(j => j.UserId, faker => faker.Random.Guid()) - .RuleFor(j => j.CronExpression, faker => faker.PickRandom( - "0 0/5 * * * ?", // Every 5 minutes - "0 0 * * * ?", // Every hour - "0 0 0 * * ?", // Every day at midnight - "0 0 0 ? * MON", // Every Monday - "0 0 0 1 * ?", // First day of month - "0 0 0 1 1 ?", // Every January 1st - "0 0 12 * * ?")) // Every noon + .RuleFor(j => j.CronExpression, faker => faker.PickRandom(_validCronExpressions)) .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } - private static Faker CreateJobScheduleViewModelFaker() + private Faker CreateJobScheduleViewModelFaker() { return new Faker() .RuleFor(j => j.Id, faker => faker.Random.Guid()) .RuleFor(j => j.UserId, faker => faker.Random.Guid()) - .RuleFor(j => j.CronExpression, faker => faker.PickRandom( - "0 0/5 * * * ?", - "0 0 * * * ?", - "0 0 0 * * ?", - "0 0 0 ? * MON", - "0 0 0 1 * ?", - "0 0 0 1 1 ?", - "0 0 12 * * ?")) + .RuleFor(j => j.CronExpression, faker => faker.PickRandom(_validCronExpressions)) .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); } diff --git a/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs index 6216551..191dfbf 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs @@ -26,7 +26,7 @@ public UserAppServiceTests() _faker = new Faker(); } - private static Faker CreateUserFaker() + private static Faker CreateFaker() { return new Faker() .RuleFor(u => u.Id, faker => faker.Random.Guid()) @@ -35,7 +35,12 @@ private static Faker CreateUserFaker() .RuleFor(u => u.Password, faker => faker.Random.AlphaNumeric(32)) .RuleFor(u => u.TelegramChatId, faker => faker.Random.Long(1000000, 9999999999)) .RuleFor(u => u.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) - .RuleFor(u => u.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); + .RuleFor(u => u.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()) + .RuleFor(u => u.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()) + .RuleFor(u => u.Invoices, _ => []) + .RuleFor(u => u.JobSchedules, _ => []) + .RuleFor(u => u.EmailAuthTokens, _ => []) + .RuleFor(u => u.ScanEmailDefinitions, _ => []); } [TestMethod] @@ -58,10 +63,8 @@ public async Task GetByEmaildAsync_WhenUserEmailExists_ShouldReturnSuccess_Whith { // Arrange var appService = new UserAppService(_repository, _unitOfWork); - var email = _faker.Internet.Email(); - var user = CreateUserFaker() - .RuleFor(u => u.Email, email) - .Generate(); + var user = CreateFaker().Generate(); + var email = user.Email; _ = _repository.GetByEmailAsync(Arg.Any(), Arg.Any()).Returns(user); diff --git a/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs b/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs index 3c3ec43..a741cad 100644 --- a/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs +++ b/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs @@ -1,5 +1,6 @@ using Bogus; using InvoiceReminder.Domain.Entities; +using InvoiceReminder.Domain.Enums; using InvoiceReminder.Domain.Extensions; using Shouldly; @@ -16,19 +17,39 @@ public sealed class UserExtensionsTests public UserExtensionsTests() { _invoiceFaker = new Faker() - .RuleFor(e => e.Id, faker => faker.Random.Guid()); + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.UserId, faker => faker.Random.Guid()) + .RuleFor(e => e.Bank, faker => faker.Company.CompanyName()) + .RuleFor(e => e.Beneficiary, faker => faker.Company.CompanyName()) + .RuleFor(e => e.Amount, faker => faker.Finance.Amount(100, 10000)) + .RuleFor(e => e.Barcode, faker => faker.Random.AlphaNumeric(44)) + .RuleFor(e => e.DueDate, faker => faker.Date.Future().ToUniversalTime()); _jobScheduleFaker = new Faker() - .RuleFor(e => e.Id, faker => faker.Random.Guid()); + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.UserId, faker => faker.Random.Guid()) + .RuleFor(e => e.CronExpression, faker => "0 9 * * *"); _emailAuthTokenFaker = new Faker() - .RuleFor(e => e.Id, faker => faker.Random.Guid()); + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.UserId, faker => faker.Random.Guid()) + .RuleFor(e => e.AccessToken, faker => faker.Random.AlphaNumeric(256)) + .RuleFor(e => e.RefreshToken, faker => faker.Random.AlphaNumeric(256)) + .RuleFor(e => e.NonceValue, faker => faker.Random.AlphaNumeric(32)) + .RuleFor(e => e.TokenProvider, faker => faker.PickRandom("Google", "Microsoft", "Yahoo")) + .RuleFor(e => e.AccessTokenExpiry, faker => faker.Date.Future().ToUniversalTime()); _scanEmailDefinitionFaker = new Faker() - .RuleFor(e => e.Id, faker => faker.Random.Guid()); + .RuleFor(e => e.Id, faker => faker.Random.Guid()) + .RuleFor(e => e.UserId, faker => faker.Random.Guid()) + .RuleFor(e => e.InvoiceType, faker => faker.PickRandom(InvoiceType.AccountInvoice, InvoiceType.BankInvoice)) + .RuleFor(e => e.Beneficiary, faker => faker.Company.CompanyName()) + .RuleFor(e => e.Description, faker => faker.Lorem.Sentence()) + .RuleFor(e => e.SenderEmailAddress, faker => faker.Internet.Email()) + .RuleFor(e => e.AttachmentFileName, faker => faker.System.FileName()); } - private static Faker UserFaker( + private static Faker CreateFaker( ICollection invoices = default, ICollection jobSchedules = default, ICollection emailAuthTokens = default, @@ -37,10 +58,13 @@ private static Faker UserFaker( return new Faker() .RuleFor(e => e.Id, faker => faker.Random.Guid()) .RuleFor(e => e.Name, faker => faker.Person.FullName) - .RuleFor(u => u.Invoices, faker => invoices ?? new HashSet()) - .RuleFor(u => u.JobSchedules, faker => jobSchedules ?? new HashSet()) - .RuleFor(u => u.EmailAuthTokens, faker => emailAuthTokens ?? new HashSet()) - .RuleFor(u => u.ScanEmailDefinitions, faker => scanEmailDefinitions ?? new HashSet()); + .RuleFor(e => e.Email, faker => faker.Internet.Email()) + .RuleFor(e => e.Password, faker => faker.Internet.Password()) + .RuleFor(e => e.TelegramChatId, faker => faker.Random.Long(1)) + .RuleFor(u => u.Invoices, _ => invoices ?? []) + .RuleFor(u => u.JobSchedules, _ => jobSchedules ?? []) + .RuleFor(u => u.EmailAuthTokens, _ => emailAuthTokens ?? []) + .RuleFor(u => u.ScanEmailDefinitions, _ => scanEmailDefinitions ?? []); } [TestMethod] @@ -48,7 +72,7 @@ public void Handle_NewUser_AddsUserToResult() { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var parameters = new UserParameters(); // Act @@ -75,7 +99,7 @@ public void Handle_NewUserWithInvoice_AddsInvoiceToUserAndResult() { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var invoice = _invoiceFaker.Generate(); var parameters = new UserParameters { Invoice = invoice }; @@ -103,7 +127,7 @@ public void Handle_NewUserWithJobSchedule_AddsJobScheduleToUserAndResult() { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var jobSchedule = _jobScheduleFaker.Generate(); var parameters = new UserParameters { JobSchedule = jobSchedule }; @@ -131,7 +155,7 @@ public void Handle_NewUserWithEmailAuthToken_AddsEmailAuthTokenToUserAndResult() { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var emailAuthToken = _emailAuthTokenFaker.Generate(); var parameters = new UserParameters { EmailAuthToken = emailAuthToken }; @@ -159,7 +183,7 @@ public void Handle_NewUserWithScanEmailDefinition_AddsScanEmailDefinitionToUserA { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var scanEmailDefinition = _scanEmailDefinitionFaker.Generate(); var parameters = new UserParameters { ScanEmailDefinition = scanEmailDefinition }; @@ -186,7 +210,7 @@ public void Handle_ExistingUserWithNewInvoice_AddsInvoiceToExistingUserInResult( { // Arrange var existingInvoice = _invoiceFaker.Generate(); - var existingUser = UserFaker(invoices: [existingInvoice]).Generate(); + var existingUser = CreateFaker(invoices: [existingInvoice]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var newInvoice = _invoiceFaker.Generate(); @@ -219,7 +243,7 @@ public void Handle_ExistingUserWithNewJobSchedule_AddsJobScheduleToExistingUserI { // Arrange var existingJobSchedule = _jobScheduleFaker.Generate(); - var existingUser = UserFaker(jobSchedules: [existingJobSchedule]).Generate(); + var existingUser = CreateFaker(jobSchedules: [existingJobSchedule]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var newJobSchedule = _jobScheduleFaker.Generate(); @@ -252,7 +276,7 @@ public void Handle_ExistingUserWithNewEmailAuthToken_AddsEmailAuthTokenToExistin { // Arrange var existingEmailAuthToken = _emailAuthTokenFaker.Generate(); - var existingUser = UserFaker(emailAuthTokens: [existingEmailAuthToken]).Generate(); + var existingUser = CreateFaker(emailAuthTokens: [existingEmailAuthToken]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var newEmailAuthToken = _emailAuthTokenFaker.Generate(); @@ -285,7 +309,7 @@ public void Handle_ExistingUserWithNewScanEmailDefinition_AddsScanEmailDefinitio { // Arrange var existingScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); - var existingUser = UserFaker(scanEmailDefinitions: [existingScanEmailDefinition]).Generate(); + var existingUser = CreateFaker(scanEmailDefinitions: [existingScanEmailDefinition]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var newScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); @@ -318,7 +342,7 @@ public void Handle_ExistingUserWithSameInvoice_DoesNotAddDuplicate() { // Arrange var existingInvoice = _invoiceFaker.Generate(); - var existingUser = UserFaker(invoices: [existingInvoice]).Generate(); + var existingUser = CreateFaker(invoices: [existingInvoice]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { Invoice = existingInvoice }; @@ -346,7 +370,7 @@ public void Handle_ExistingUserWithSameJobSchedule_DoesNotAddDuplicate() { // Arrange var existingJobSchedule = _jobScheduleFaker.Generate(); - var existingUser = UserFaker(jobSchedules: [existingJobSchedule]).Generate(); + var existingUser = CreateFaker(jobSchedules: [existingJobSchedule]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { JobSchedule = existingJobSchedule }; @@ -374,7 +398,7 @@ public void Handle_ExistingUserWithSameEmailAuthToken_DoesNotAddDuplicate() { // Arrange var existingEmailAuthToken = _emailAuthTokenFaker.Generate(); - var existingUser = UserFaker(emailAuthTokens: [existingEmailAuthToken]).Generate(); + var existingUser = CreateFaker(emailAuthTokens: [existingEmailAuthToken]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { EmailAuthToken = existingEmailAuthToken }; @@ -402,7 +426,7 @@ public void Handle_ExistingUserWithSameScanEmailDefinition_DoesNotAddDuplicate() { // Arrange var existingScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); - var existingUser = UserFaker(scanEmailDefinitions: [existingScanEmailDefinition]).Generate(); + var existingUser = CreateFaker(scanEmailDefinitions: [existingScanEmailDefinition]).Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var parameters = new UserParameters { ScanEmailDefinition = existingScanEmailDefinition }; @@ -430,7 +454,7 @@ public void Handle_NewUserWithEmptyCollections_InitializesCollections() { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var invoice = _invoiceFaker.Generate(); var jobSchedule = _jobScheduleFaker.Generate(); var scanEmailDefinition = _scanEmailDefinitionFaker.Generate(); @@ -473,7 +497,7 @@ public void Handle_NewUserWithEmptyCollections_InitializesCollections() public void Handle_ExistingUserWithNullCollections_AddsNewItems() { // Arrange - var existingUser = UserFaker().Generate(); + var existingUser = CreateFaker().Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; var newUserReference = existingUser; var invoice = _invoiceFaker.Generate(); @@ -524,12 +548,12 @@ public void Handle_ExistingUserWithNullParameters_DoesNotModifyUser() // Arrange var existingInvoice = _invoiceFaker.Generate(); var existingJobSchedule = _jobScheduleFaker.Generate(); - var exitingEmailAuthToken = _emailAuthTokenFaker.Generate(); + var existingEmailAuthToken = _emailAuthTokenFaker.Generate(); var existingScanEmailDefinition = _scanEmailDefinitionFaker.Generate(); - var existingUser = UserFaker( + var existingUser = CreateFaker( invoices: [existingInvoice], jobSchedules: [existingJobSchedule], - emailAuthTokens: [exitingEmailAuthToken], + emailAuthTokens: [existingEmailAuthToken], scanEmailDefinitions: [existingScanEmailDefinition]) .Generate(); var result = new Dictionary { { existingUser.Id, existingUser } }; @@ -551,7 +575,7 @@ public void Handle_ExistingUserWithNullParameters_DoesNotModifyUser() result.ShouldContainKey(existingUser.Id); result[existingUser.Id].Invoices.ShouldContain(existingInvoice); result[existingUser.Id].JobSchedules.ShouldContain(existingJobSchedule); - result[existingUser.Id].EmailAuthTokens.ShouldContain(exitingEmailAuthToken); + result[existingUser.Id].EmailAuthTokens.ShouldContain(existingEmailAuthToken); result[existingUser.Id].ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); result[existingUser.Id].Invoices.Count.ShouldBe(1); result[existingUser.Id].JobSchedules.Count.ShouldBe(1); @@ -567,7 +591,7 @@ public void Handle_ExistingUserWithNullParameters_DoesNotModifyUser() newUserReference.ScanEmailDefinitions.Count.ShouldBe(1); newUserReference.Invoices.ShouldContain(existingInvoice); newUserReference.JobSchedules.ShouldContain(existingJobSchedule); - newUserReference.EmailAuthTokens.ShouldContain(exitingEmailAuthToken); + newUserReference.EmailAuthTokens.ShouldContain(existingEmailAuthToken); newUserReference.ScanEmailDefinitions.ShouldContain(existingScanEmailDefinition); }); } @@ -577,7 +601,7 @@ public void Handle_NewUserWithNullParameters_AddsUserWithEmptyCollections() { // Arrange var result = new Dictionary(); - var user = UserFaker().Generate(); + var user = CreateFaker().Generate(); var parameters = new UserParameters { Invoice = null, diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs index 4ea886e..e96f2a8 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs @@ -207,7 +207,7 @@ public async Task Update_Should_UpdateExistingEntity() _ = await repository.AddAsync(entity, TestContext.CancellationToken); _ = await context.SaveChangesAsync(TestContext.CancellationToken); - var updatedName = new Faker().Lorem.Word(); + var updatedName = _testEntityFaker.Generate().Name; entity.Name = updatedName; // Act @@ -239,7 +239,7 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() _ = context.Attach(entity); context.Entry(entity).State = EntityState.Detached; - var updatedName = new Faker().Lorem.Word(); + var updatedName = _testEntityFaker.Generate().Name; entity.Name = updatedName; // Act diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs index 71fc625..214f7b7 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/ScanEmailDefinitionRepositoryTests.cs @@ -17,7 +17,6 @@ public sealed class ScanEmailDefinitionRepositoryTests private readonly CoreDbContext _dbContext; private readonly ILogger _logger; private readonly IScanEmailDefinitionRepository _repository; - private Faker _scanEmailDefinitionFaker; public TestContext TestContext { get; set; } @@ -32,15 +31,9 @@ public ScanEmailDefinitionRepositoryTests() _repository = Substitute.For(); } - [TestInitialize] - public void Setup() + private static Faker CreateFaker(Action> configure = null) { - InitializeFaker(); - } - - private void InitializeFaker() - { - _scanEmailDefinitionFaker = new Faker() + var faker = new Faker() .RuleFor(s => s.Id, _ => Guid.NewGuid()) .RuleFor(s => s.UserId, _ => Guid.NewGuid()) .RuleFor(s => s.InvoiceType, f => f.PickRandom()) @@ -48,6 +41,10 @@ private void InitializeFaker() .RuleFor(s => s.Description, f => f.Lorem.Sentence()) .RuleFor(s => s.SenderEmailAddress, f => f.Internet.Email()) .RuleFor(s => s.AttachmentFileName, f => f.System.FileName()); + + configure?.Invoke(faker); + + return faker; } [TestMethod] @@ -74,7 +71,7 @@ public async Task GetBySenderBeneficiaryAsync_ShouldReturnScanEmailDefinition_Wh // Arrange var userId = Guid.NewGuid(); var beneficiary = new Faker().Company.CompanyName(); - var scanEmailDefinition = _scanEmailDefinitionFaker + var scanEmailDefinition = CreateFaker() .RuleFor(s => s.UserId, _ => userId) .RuleFor(s => s.Beneficiary, _ => beneficiary) .Generate(); @@ -101,7 +98,7 @@ public async Task GetBySenderEmailAsync_ShouldReturnScanEmailDefinition_WhenScan // Arrange var userId = Guid.NewGuid(); var senderEmail = new Faker().Internet.Email(); - var scanEmailDefinition = _scanEmailDefinitionFaker + var scanEmailDefinition = CreateFaker() .RuleFor(s => s.UserId, _ => userId) .RuleFor(s => s.SenderEmailAddress, _ => senderEmail) .Generate(); @@ -127,7 +124,7 @@ public async Task GetByUserIdAsync_ShouldReturnScanEmailDefinition_WhenScanEmail { // Arrange var userId = Guid.NewGuid(); - var collection = _scanEmailDefinitionFaker + var collection = CreateFaker() .RuleFor(s => s.UserId, _ => userId) .Generate(2); diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs index 988ebf7..46ec4da 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UserRepositoryTests.cs @@ -16,7 +16,6 @@ public sealed class UserRepositoryTests private readonly CoreDbContext _dbContext; private readonly ILogger _logger; private readonly IUserRepository _repository; - private Faker _userFaker; public TestContext TestContext { get; set; } @@ -31,15 +30,9 @@ public UserRepositoryTests() _repository = Substitute.For(); } - [TestInitialize] - public void Setup() + private static Faker CreateFaker() { - InitializeFaker(); - } - - private void InitializeFaker() - { - _userFaker = new Faker() + return new Faker() .RuleFor(u => u.Id, _ => Guid.NewGuid()) .RuleFor(u => u.TelegramChatId, f => f.Random.Long(100000000, long.MaxValue)) .RuleFor(u => u.Name, f => f.Person.FullName) @@ -70,7 +63,7 @@ public async Task GetByEmailAsync_ShouldReturnUser_WhenUserExists() { // Arrange var email = new Faker().Internet.Email(); - var user = _userFaker + var user = CreateFaker() .RuleFor(u => u.Email, _ => email) .Generate(); @@ -95,7 +88,7 @@ public async Task GetByIdAsync_ShouldReturnUser_WhenUserExists() { // Arrange var userId = Guid.NewGuid(); - var user = _userFaker + var user = CreateFaker() .RuleFor(u => u.Id, _ => userId) .Generate(); From 44adadc18d3cb4cb541467cf113f277f2806d81c Mon Sep 17 00:00:00 2001 From: "Jefferson L. da Silva" Date: Fri, 19 Dec 2025 11:27:41 -0300 Subject: [PATCH 3/5] Refactoring based on code review --- .github/workflows/workflow-ci.yml | 4 ++-- .../AppServices/BaseAppServiceTests.cs | 10 ++++++---- .../AppServices/JobScheduleAppServiceTests.cs | 8 ++++---- .../AppServices/UserAppServiceTests.cs | 5 ++--- .../Extensions/UserExtensionsTests.cs | 4 ++-- .../Data/Repository/BaseRepositoryTests.cs | 16 ++++++++++------ 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/.github/workflows/workflow-ci.yml b/.github/workflows/workflow-ci.yml index 4a8cea5..48b1940 100644 --- a/.github/workflows/workflow-ci.yml +++ b/.github/workflows/workflow-ci.yml @@ -27,8 +27,8 @@ jobs: sudo apt-get update sudo apt-get install -y locales sudo locale-gen en_US.UTF-8 - export LANG=en_US.UTF-8 - export LC_ALL=en_US.UTF-8 + echo "LANG=en_US.UTF-8" >> $GITHUB_ENV + echo "LC_ALL=en_US.UTF-8" >> $GITHUB_ENV - name: Restore dependencies run: dotnet restore diff --git a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs index a425f67..fac8462 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs @@ -28,14 +28,16 @@ public BaseAppServiceTests() _entityFaker = new Faker() .RuleFor(e => e.Id, faker => faker.Random.Guid()) .RuleFor(e => e.Name, faker => faker.Person.FullName) - .RuleFor(e => e.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) - .RuleFor(e => e.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); + .RuleFor(e => e.CreatedAt, faker => faker.Date.Past(1).ToUniversalTime()) + .RuleFor(e => e.UpdatedAt, (faker, entity) => faker.Date.Between(entity.CreatedAt, DateTime.UtcNow) + .ToUniversalTime()); _entityViewModelFaker = new Faker() .RuleFor(e => e.Id, faker => faker.Random.Guid()) .RuleFor(e => e.Name, faker => faker.Person.FullName) - .RuleFor(e => e.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) - .RuleFor(e => e.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); + .RuleFor(e => e.CreatedAt, faker => faker.Date.Past(1).ToUniversalTime()) + .RuleFor(e => e.UpdatedAt, (faker, entity) => faker.Date.Between(entity.CreatedAt, DateTime.UtcNow) + .ToUniversalTime()); } [TestMethod] diff --git a/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs index 9001ce8..4c5a3cf 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/JobScheduleAppServiceTests.cs @@ -47,8 +47,8 @@ private Faker CreateJobScheduleFaker() .RuleFor(j => j.Id, faker => faker.Random.Guid()) .RuleFor(j => j.UserId, faker => faker.Random.Guid()) .RuleFor(j => j.CronExpression, faker => faker.PickRandom(_validCronExpressions)) - .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) - .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); + .RuleFor(j => j.CreatedAt, faker => faker.Date.Past(refDate: DateTime.UtcNow).ToUniversalTime()) + .RuleFor(j => j.UpdatedAt, (faker, j) => faker.Date.Between(j.CreatedAt, DateTime.UtcNow).ToUniversalTime()); } private Faker CreateJobScheduleViewModelFaker() @@ -57,8 +57,8 @@ private Faker CreateJobScheduleViewModelFaker() .RuleFor(j => j.Id, faker => faker.Random.Guid()) .RuleFor(j => j.UserId, faker => faker.Random.Guid()) .RuleFor(j => j.CronExpression, faker => faker.PickRandom(_validCronExpressions)) - .RuleFor(j => j.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) - .RuleFor(j => j.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()); + .RuleFor(j => j.CreatedAt, faker => faker.Date.Past(refDate: DateTime.UtcNow).ToUniversalTime()) + .RuleFor(j => j.UpdatedAt, (faker, j) => faker.Date.Between(j.CreatedAt, DateTime.UtcNow).ToUniversalTime()); } [TestMethod] diff --git a/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs index 191dfbf..e2e420c 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/UserAppServiceTests.cs @@ -32,11 +32,10 @@ private static Faker CreateFaker() .RuleFor(u => u.Id, faker => faker.Random.Guid()) .RuleFor(u => u.Name, faker => faker.Person.FullName) .RuleFor(u => u.Email, faker => faker.Internet.Email()) - .RuleFor(u => u.Password, faker => faker.Random.AlphaNumeric(32)) - .RuleFor(u => u.TelegramChatId, faker => faker.Random.Long(1000000, 9999999999)) + .RuleFor(u => u.Password, faker => faker.Internet.Password()) + .RuleFor(u => u.TelegramChatId, faker => faker.Random.Long(100000000, long.MaxValue)) .RuleFor(u => u.CreatedAt, faker => faker.Date.Past().ToUniversalTime()) .RuleFor(u => u.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()) - .RuleFor(u => u.UpdatedAt, faker => faker.Date.Recent().ToUniversalTime()) .RuleFor(u => u.Invoices, _ => []) .RuleFor(u => u.JobSchedules, _ => []) .RuleFor(u => u.EmailAuthTokens, _ => []) diff --git a/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs b/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs index a741cad..fd37453 100644 --- a/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs +++ b/InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs @@ -22,13 +22,13 @@ public UserExtensionsTests() .RuleFor(e => e.Bank, faker => faker.Company.CompanyName()) .RuleFor(e => e.Beneficiary, faker => faker.Company.CompanyName()) .RuleFor(e => e.Amount, faker => faker.Finance.Amount(100, 10000)) - .RuleFor(e => e.Barcode, faker => faker.Random.AlphaNumeric(44)) + .RuleFor(e => e.Barcode, faker => faker.Random.Replace("############################################")) .RuleFor(e => e.DueDate, faker => faker.Date.Future().ToUniversalTime()); _jobScheduleFaker = new Faker() .RuleFor(e => e.Id, faker => faker.Random.Guid()) .RuleFor(e => e.UserId, faker => faker.Random.Guid()) - .RuleFor(e => e.CronExpression, faker => "0 9 * * *"); + .RuleFor(e => e.CronExpression, faker => $"0 {faker.Random.Int(0, 23)} * * *"); _emailAuthTokenFaker = new Faker() .RuleFor(e => e.Id, faker => faker.Random.Guid()) diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs index e96f2a8..5e64cc5 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs @@ -261,12 +261,16 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() public async Task Where_Should_ReturnEntitiesMatchingPredicate() { // Arrange - var entities = new List - { - _testEntityFaker.RuleFor(e => e.Name, _ => "Test1").Generate(), - _testEntityFaker.RuleFor(e => e.Name, _ => "AnotherTest").Generate(), - _testEntityFaker.RuleFor(e => e.Name, _ => "Test2").Generate() - }; + var entity1 = _testEntityFaker.Generate(); + entity1.Name = "Test1"; + + var entity2 = _testEntityFaker.Generate(); + entity2.Name = "AnotherTest"; + + var entity3 = _testEntityFaker.Generate(); + entity3.Name = "Test2"; + + var entities = new List { entity1, entity2, entity3 }; using var context = CreateContext(); context.TestEntities.AddRange(entities); From 13926b72f3fac0ace66e7d228c03dbfc2cfd5dc9 Mon Sep 17 00:00:00 2001 From: "Jefferson L. da Silva" Date: Fri, 19 Dec 2025 13:01:42 -0300 Subject: [PATCH 4/5] Fixing some nitpicks from code review --- .../AppServices/BaseAppServiceTests.cs | 2 +- .../Data/Repository/BaseRepositoryTests.cs | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs index fac8462..12ea633 100644 --- a/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs +++ b/InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs @@ -172,7 +172,7 @@ public async Task GetByIdAsync_Should_Return_Success_When_Entity_Exists() _ = _repository.GetByIdAsync(Arg.Any(), Arg.Any()).Returns(entity); // Act - var result = await _appService.GetByIdAsync(Guid.NewGuid(), TestContext.CancellationToken); + var result = await _appService.GetByIdAsync(entity.Id, TestContext.CancellationToken); // Assert _ = _repository.Received(1).GetByIdAsync(Arg.Any(), Arg.Any()); diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs index 5e64cc5..61b6c94 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs @@ -207,8 +207,7 @@ public async Task Update_Should_UpdateExistingEntity() _ = await repository.AddAsync(entity, TestContext.CancellationToken); _ = await context.SaveChangesAsync(TestContext.CancellationToken); - var updatedName = _testEntityFaker.Generate().Name; - entity.Name = updatedName; + entity.Name = new Faker().Name.FullName(); // Act var updatedEntity = repository.Update(entity); @@ -221,7 +220,7 @@ public async Task Update_Should_UpdateExistingEntity() retrievedEntity.ShouldSatisfyAllConditions(() => { _ = retrievedEntity.ShouldNotBeNull(); - retrievedEntity.Name.ShouldBe(updatedName); + retrievedEntity.Name.ShouldBe(entity.Name); }); } @@ -239,8 +238,7 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() _ = context.Attach(entity); context.Entry(entity).State = EntityState.Detached; - var updatedName = _testEntityFaker.Generate().Name; - entity.Name = updatedName; + entity.Name = new Faker().Name.FullName(); // Act var updatedEntity = repository.Update(entity); @@ -253,7 +251,7 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() retrievedEntity.ShouldSatisfyAllConditions(() => { _ = retrievedEntity.ShouldNotBeNull(); - retrievedEntity.Name.ShouldBe(updatedName); + retrievedEntity.Name.ShouldBe(entity.Name); }); } From 9426c2d1f255a0d792ae74de5445eef8bfdb6182 Mon Sep 17 00:00:00 2001 From: "Jefferson L. da Silva" Date: Fri, 19 Dec 2025 13:16:28 -0300 Subject: [PATCH 5/5] Fixing last nitpick from code review --- .../Data/Repository/BaseRepositoryTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs index 61b6c94..a9ca8c5 100644 --- a/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs +++ b/InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs @@ -207,7 +207,7 @@ public async Task Update_Should_UpdateExistingEntity() _ = await repository.AddAsync(entity, TestContext.CancellationToken); _ = await context.SaveChangesAsync(TestContext.CancellationToken); - entity.Name = new Faker().Name.FullName(); + entity.Name = _testEntityFaker.Generate().Name; // Act var updatedEntity = repository.Update(entity); @@ -238,7 +238,7 @@ public async Task Update_Should_AttachAndUpdateDetachedEntity() _ = context.Attach(entity); context.Entry(entity).State = EntityState.Detached; - entity.Name = new Faker().Name.FullName(); + entity.Name = _testEntityFaker.Generate().Name; // Act var updatedEntity = repository.Update(entity);