Skip to content

Updates project to .NET 10#64

Merged
jldsilva merged 3 commits into
developmentfrom
dotNet10-Update
Dec 5, 2025
Merged

Updates project to .NET 10#64
jldsilva merged 3 commits into
developmentfrom
dotNet10-Update

Conversation

@jldsilva

@jldsilva jldsilva commented Dec 4, 2025

Copy link
Copy Markdown
Owner

Migrates the project to .NET 10. This involves updating the target framework in project files and the Dockerfile.

Adds a central package management file to manage package versions.
Also adds a CI workflow to run unit tests on pull requests.

Removes unused references and updates test projects to use MSTest runner.

Updates logging implementation with logger enabled check.

Summary by CodeRabbit

Notas de Versão

  • New Features

    • Documentação da API ampliada com coleções de endpoints e exemplos.
  • Refactor

    • Migração para .NET 10 e atualização de pacotes.
    • Substituição da solução de operações em lote por alternativa moderna.
    • Inicialização automática de coleções em entidades e extensão para inserção deduplicada.
    • Logging otimizado com verificações de nível antes de emitir mensagens.
  • Tests

    • Novos testes cobrindo a lógica de inserção deduplicada e ajustes em testes existentes.
  • Chores

    • Centralização de configurações em arquivos globais; CI e imagem de container atualizados.

✏️ Tip: You can customize this high-level summary in your review settings.

Migrates the project to .NET 10. This involves updating the target framework in project files and the Dockerfile.

Adds a central package management file to manage package versions.
Also adds a CI workflow to run unit tests on pull requests.

Removes unused references and updates test projects to use MSTest runner.

Updates logging implementation with logger enabled check.
@jldsilva jldsilva self-assigned this Dec 4, 2025
@jldsilva jldsilva added .NET Pull requests that update .NET code dependencies Pull requests that update a dependency file labels Dec 4, 2025
@coderabbitai

coderabbitai Bot commented Dec 4, 2025

Copy link
Copy Markdown

Walkthrough

Migração do repositório para .NET 10: centralização de props e pacotes, atualização de CI/Docker, inicialização de coleções em entidades/viewmodels, introdução de AddIfNotExists com testes, e aplicação de guards de logging IsEnabled em vários repositórios e serviços.

Changes

Cohort / File(s) Resumo das Mudanças
CI e build centralizado
/.github/workflows/workflow-ci.yml, Directory.Build.props, Directory.Packages.props, InvoiceReminder.sln
CI e solução atualizados para .NET 10; novo Directory.Build.props com propriedades globais; massiva atualização/reorganização de pacotes para 10.0.0; solução apontando para VS18.
Remoção de PropertyGroup em projetos
InvoiceReminder.*/*.csproj, InvoiceReminder.*/*/*.csproj (vários)
Remoção de PropertyGroup locais (TargetFramework, ImplicitUsings, Nullable, UserSecretsId) para herdar das props centrais.
Projetos de teste: runner/configuração
**/*UnitTests.csproj, **/ArchitectureTests/*.csproj, **/DomainEntities.UnitTests/*.csproj
Substituição de flags legadas por EnableMSTestRunner, OutputType: Exe, UseVSTest: false; remoção de pacotes de trx/codecoverage obsoletos.
Docker / imagem
InvoiceReminder.API/Dockerfile
Base runtime/SDK atualizados para 10.x; instala libgssapi-krb5-2; copia Directory.Build.props antes do restore; ajustes de ordem de build.
Testes — classes sealed e asserts de logging
InvoiceReminder.API.UnitTests/..., InvoiceReminder.Application.UnitTests/..., InvoiceReminder.DomainEntities.UnitTests/..., InvoiceReminder.ExternalServices.UnitTests/..., InvoiceReminder.Infrastructure.UnitTests/..., InvoiceReminder.JobScheduler.UnitTests/...
Várias classes de teste tornadas sealed; asserts de logging refatoradas para usar _logger.IsEnabled(...) e verificações com argumentos explícitos.
Guards de logging (IsEnabled) e templates
InvoiceReminder.Data/Repository/*, InvoiceReminder.ExternalServices/*, InvoiceReminder.JobScheduler/*
Substituição de logs incondicionais por chamadas condicionais verificando _logger.IsEnabled(...); introdução de constantes de template de mensagem em vários arquivos.
Migração Bulk / EF Core
InvoiceReminder.Data/InvoiceReminder.Data.csproj, InvoiceReminder.Data/Repository/BaseRepository.cs
Substituição de EFCore.BulkExtensions por Z.EntityFramework.Extensions.EFCore; ajuste de IncludeAssets e chamada positional em BulkInsertAsync.
OpenAPI / Security
InvoiceReminder.API/AuthenticationSetup/BearerSecuritySchemeTransformer.cs, InvoiceReminder.API.UnitTests/...BearerSecuritySchemeTransformerTests.cs
Import trocado para Microsoft.OpenApi; uso de Dictionary<string, IOpenApiSecurityScheme> com cast explícito.
Documentação HTTP
InvoiceReminder.API/InvoiceReminder.http
Substituição do exemplo weatherforecast por documentação extensa de endpoints (LOGIN, USER, INVOICE, JOB SCHEDULE, SCAN EMAIL DEFINITION, GOOGLE OAUTH).
Entidades, extensões e testes
InvoiceReminder.Domain/Entities/User.cs, InvoiceReminder.Domain/Extensions/EntityExtensions.cs, InvoiceReminder.Domain/Extensions/UserExtensions.cs, InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs, InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs
Adiciona construtor em User inicializando coleções; novo AddIfNotExists<T> com comparer reflexivo e testes que cobrem deduplicação e cenários nulos/vazios; refatoração de UserExtensions para usar o helper.
ViewModel — inicialização de coleções
InvoiceReminder.Application/ViewModels/UserViewModel.cs
Inicializa Invoices, JobSchedules, ScanEmailDefinitions como arrays vazios no construtor.

Estimated code review effort

🎯 3 (Moderada) | ⏱️ ~20 minutos

  • Pontos que merecem atenção:
    • Implementação reflexiva de GetId em EntityExtensions (validações, exceções e performance).
    • Substituição e compatibilidade da biblioteca de bulk (Z.EntityFramework.Extensions.EFCore) e chamadas de BulkInsertAsync.
    • Propagação/leitura correta das props globais (Directory.Build.props) durante build/CI/Docker.
    • Refatorações nos testes que agora exigem _logger.IsEnabled(...) — confirmar que não introduziram falsos positivos/negativos.

Possibly related PRs

"
🐇 Saltei do nove pro dez, felicíssimo,
Props no bolso, pacotes brilhando,
Coleções já prontas, sem risco indeciso,
Logs só cantam quando estão escutando.
Viva o patch — minha toca está dançando!
"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título descreve com precisão a mudança principal do conjunto de alterações: a migração para .NET 10.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dotNet10-Update

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b392e76 and 63d228d.

📒 Files selected for processing (1)
  • InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • InvoiceReminder.Domain/Extensions/EntityExtensions.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (csharp)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (1)

52-69: Remove redundant guard from test assertions and verify IsEnabled call behavior.

The test mocks IsEnabled to always return true (line 52), then wraps the assertion in a guard if (_logger.IsEnabled(LogLevel.Information)) (lines 62-69). Since the mock always returns true, this guard is redundant and obscures what the test is actually verifying.

Issues:

  1. Guard in assertions is redundant: With IsEnabled mocked to return true, the condition always passes, making the guard meaningless.
  2. Missing verification: The test never verifies that IsEnabled(LogLevel.Information) was actually called by the production code.
  3. Incomplete coverage: No test scenario for when IsEnabled returns false, which the production code explicitly handles (line 28-31 in CronJob.cs).

Recommended fixes:

  • Remove the guard from the assertion block—assertions should be direct and unconditional
  • Add verification that _logger.Received(1).IsEnabled(LogLevel.Information) was called
  • Add a second test scenario where IsEnabled returns false and verify logging does not occur
InvoiceReminder.JobScheduler/HostedService/QuartzHostedService.cs (1)

31-49: Guard de log está correto, mas o segundo construtor pode levar a NullReferenceException

  • O novo guard com _logger.IsEnabled(LogLevel.Error) em volta do LogError em caso de expressão cron inválida está consistente com o restante do código e não altera o fluxo de controle (a iteração continua com continue).
  • Porém, o segundo construtor (QuartzHostedService(IJobFactory jobFactory, ISchedulerFactory schedulerFactory)) não inicializa _logger nem _schedules. Se esse construtor for usado e a expressão cron for inválida, a chamada a _logger.IsEnabled(...) resultará em NRE (e _schedules também poderá ser null em qualquer iteração).

Sugestões:

  • Ou remova o segundo construtor se não for mais necessário,
  • ou faça com que ele delegue para o construtor principal, fornecendo um ILogger e uma coleção vazia de JobSchedule,
  • ou inicialize explicitamente _logger com um logger “neutro” e _schedules com [].

Isso evita falhas em tempo de execução difíceis de diagnosticar.

♻️ Duplicate comments (2)
InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (1)

102-119: Mesmo problema de padrão de teste com guard de logging.

Este teste apresenta o mesmo problema de design identificado nas linhas 52-69: guard redundante no teste que não verifica adequadamente o comportamento do código de produção.

InvoiceReminder.API/InvoiceReminder.API.csproj (1)

21-21: Verifique se a remoção de contentfiles não afeta as ferramentas de design do EF Core.

A remoção de contentfiles dos IncludeAssets para Microsoft.EntityFrameworkCore.Design pode afetar ferramentas de design-time. Esta mesma alteração foi aplicada em InvoiceReminder.Data.csproj e requer verificação em ambos os projetos.

🧹 Nitpick comments (12)
InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1)

3-22: Sugerir interface ou constraint para garantir presença da propriedade Id.

O método usa reflexão porque não há garantia em tempo de compilação de que o tipo T possui uma propriedade Id. Isso resulta em código frágil e lento.

Considere criar uma interface para entidades com Id:

// Adicionar em um arquivo de infraestrutura
public interface IEntity
{
    Guid Id { get; }
}

// Atualizar suas entidades
public class User : EntityDefaults, IEntity
{
    // ... propriedades existentes
}

Em seguida, refatore a extensão:

 public static class EntityExtensions
 {
-    public static void AddIfNotExists<T>(this T entity, ICollection<T> collection) where T : class
+    public static void AddIfNotExists<T>(this T entity, ICollection<T> collection) where T : class, IEntity
     {
         if (entity is null)
         {
             return;
         }

-        if (collection.FirstOrDefault(e => GetId(e).Equals(GetId(entity))) is null)
+        if (!collection.Any(e => e.Id == entity.Id))
         {
             collection.Add(entity);
         }
     }
-
-    private static Guid GetId<T>(T entity) where T : class
-    {
-        return (Guid)typeof(T).GetProperty("Id")!.GetValue(entity)!;
-    }
 }

Benefícios:

  • Segurança em tempo de compilação
  • Melhor desempenho (sem reflexão)
  • IntelliSense e refatoração funcionam corretamente
InvoiceReminder.ExternalServices/BarcodeReader/BarcodeReaderService.cs (1)

21-32: Guard de log está ok, mas há pequenos pontos de melhoria

  • O guard com _logger.IsEnabled(LogLevel.Error) em torno do LogError está consistente com o padrão adotado no PR, sem alterar o fluxo de exceção.
  • O template "{Messagem}" tem um pequeno typo; se for usado em consultas/alertas, considere padronizar para algo como "{Message}" ou um nome em pt-BR coerente (ex.: "{ErrorMessage}") para facilitar análise posterior.
  • Fora do trecho alterado, note que se invoiceType receber um valor não tratado no switch, _barcodeHandler fica null e CreateInvoice gerará NullReferenceException. Pode valer a pena lançar uma exceção mais clara ou ter um handler padrão para evitar um NRE difícil de rastrear.
InvoiceReminder.ExternalServices/Telegram/TelegramMessageService.cs (1)

34-44: Uso de IsEnabled em erros do Telegram está consistente

Os guards com _logger.IsEnabled(LogLevel.Error) nos dois catch mantêm o comportamento atual (apenas logar e não propagar a exceção), reduzindo overhead quando o nível Error estiver desabilitado.

Como melhoria opcional, você poderia incluir mais contexto nos logs (por exemplo, chatId ou um identificador de correlação), para facilitar troubleshooting de falhas específicas de envio.

InvoiceReminder.Data/Repository/UserRepository.cs (1)

18-19: Padrão de logging padronizado e bem aplicado

  • A constante LogExceptionMessage centraliza o template e ajuda a manter consistência entre os logs do repositório.
  • Os guards com _logger.IsEnabled(LogLevel.Warning/Error) antes de logar em cenários de cancelamento e exceção genérica evitam trabalho desnecessário quando o nível correspondente estiver desabilitado.
  • As mensagens continuam ricas em contexto (contextualInfo) e você mantém o padrão de reempacotar em OperationCanceledException/DataLayerException, preservando a pilha original (ex).

Alteração bem alinhada ao restante do PR, sem impactos negativos aparentes.

Also applies to: 68-71, 80-83, 122-125, 134-137

InvoiceReminder.API/InvoiceReminder.http (1)

198-260: Ajustes opcionais nos exemplos de cron e rotas

Alguns ajustes que podem deixar os exemplos ainda mais fiéis ao comportamento real:

  • Os exemplos de cronExpression ("0 0 * * *", "0 0 * * 1") usam 5 campos; se o agendador estiver esperando 6/7 campos (incluindo segundos), talvez valha alinhar o exemplo ao formato realmente aceito para evitar erro de validação quando alguém copiar/colar.
  • Em vários endpoints de deleção (DELETE /api/user, /api/invoice, /api/job_schedule, /api/scan_email) o id vem no corpo em vez de na rota. Se a API real aceitar apenas rota (ou ambos), pode ser útil acrescentar um comentário informando isso para evitar confusão.

Nada bloqueante, apenas refinamentos para tornar o arquivo 100% consistente com o comportamento da API.

InvoiceReminder.ExternalServices/Gmail/GoogleOAuthService.cs (1)

176-183: Considere aplicar logging guardado de forma consistente.

O método RefreshAuthTokenAsync relança a exceção sem logging, o que é adequado neste contexto. Porém, se futuramente for adicionado logging aqui, mantenha o mesmo padrão de guarda IsEnabled utilizado nos outros métodos.

InvoiceReminder.ExternalServices.UnitTests/SendMessage/SendMessageServiceTests.cs (2)

122-130: Verificação condicional desnecessária no teste.

O bloco if (_logger.IsEnabled(LogLevel.Error)) é redundante aqui. O mock já foi configurado para retornar true na linha 115, então este if sempre será executado. Isso adiciona complexidade sem valor ao teste.

Remova o if e mantenha apenas a verificação:

-        if (_logger.IsEnabled(LogLevel.Error))
-        {
-            var eventId = Arg.Any<EventId>();
-            var state = Arg.Is<object>(o => o.ToString().Contains("User not found"));
-            var loggedException = Arg.Any<Exception>();
-            var formatter = Arg.Any<Func<object, Exception, string>>();
-
-            _logger.Received(1).Log(LogLevel.Error, eventId, state, loggedException, formatter);
-        }
+        var eventId = Arg.Any<EventId>();
+        var state = Arg.Is<object>(o => o.ToString().Contains("User not found"));
+        var loggedException = Arg.Any<Exception>();
+        var formatter = Arg.Any<Func<object, Exception, string>>();
+
+        _logger.Received(1).Log(LogLevel.Error, eventId, state, loggedException, formatter);

158-166: Verificação condicional desnecessária no teste.

Mesmo problema do teste anterior. O bloco if é redundante pois o mock já foi configurado para retornar true.

Remova o if e mantenha apenas a verificação:

-        if (_logger.IsEnabled(LogLevel.Warning))
-        {
-            var eventId = Arg.Any<EventId>();
-            var state = Arg.Is<object>(o => o.ToString().Contains("No Authentication Token found"));
-            var loggedException = Arg.Is<Exception>(e => e == null);
-            var formatter = Arg.Any<Func<object, Exception, string>>();
-
-            _logger.Received(1).Log(LogLevel.Warning, eventId, state, loggedException, formatter);
-        }
+        var eventId = Arg.Any<EventId>();
+        var state = Arg.Is<object>(o => o.ToString().Contains("No Authentication Token found"));
+        var loggedException = Arg.Is<Exception>(e => e == null);
+        var formatter = Arg.Any<Func<object, Exception, string>>();
+
+        _logger.Received(1).Log(LogLevel.Warning, eventId, state, loggedException, formatter);
InvoiceReminder.Data/Repository/EmailAuthTokenRepository.cs (1)

16-16: Padronização de logging de exceções ficou boa

A constante LogExceptionMessage e o uso de _logger.IsEnabled com LogWarning/LogError deixam o logging mais consistente e previsível, sem alterar o fluxo das exceções (cancelamento continua virando OperationCanceledException e demais erros viram DataLayerException). Se quiser evoluir depois, daria para extrair esse padrão (template + contextualInfo) para um helper compartilhado entre os repositórios a fim de reduzir repetição, mas não é obrigatório agora.

Also applies to: 43-46, 55-58

InvoiceReminder.Data/Repository/ScanEmailDefinitionRepository.cs (1)

16-16: Logging de exceções está consistente em todos os métodos

O uso de LogExceptionMessageTemplate combinado com IsEnabled e LogWarning/LogError padroniza bem o tratamento de falhas nas três operações (GetBySenderBeneficiaryAsync, GetBySenderEmailAddressAsync e GetByUserIdAsync), mantendo o mesmo contexto nas mensagens e sem mudar o comportamento das exceções. Como isso se repete em vários repositórios, pode valer no futuro extrair um utilitário comum (por exemplo, um helper estático ou método protegido em BaseRepository) para reduzir duplicação, mas não é algo bloqueante.

Also applies to: 44-47, 56-59, 87-90, 99-102, 129-132, 141-144

InvoiceReminder.API/Dockerfile (1)

4-4: Atualização para .NET 10 e dependência nativa parecem corretas

A troca das imagens para aspnet:10.0/sdk:10.0, a instalação da libgssapi-krb5-2 com elevação temporária para root e o uso de Directory.Build.props/Directory.Packages.props antes do restore estão todos consistentes com o objetivo de migrar para .NET 10 e centralizar configuração. Como melhoria opcional, você poderia adicionar --no-install-recommends ao apt-get install para reduzir o tamanho da imagem.

Also applies to: 11-16, 19-19, 23-23

InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UnitOfWorkTests.cs (1)

70-88: Considere simplificar as asserções de logging no teste.

O padrão atual configura o mock para retornar true em IsEnabled (linha 70) e depois verifica essa condição novamente antes de fazer as asserções (linhas 80-88). Como o teste controla o mock, a verificação condicional é redundante—o bloco sempre será executado.

Se não houver um padrão arquitetural estabelecido para isso, considere simplificar:

         _ = context.Users.Add(new User { Id = Guid.NewGuid() });
         _ = _logger.IsEnabled(Arg.Any<LogLevel>()).Returns(true);

         // Act
         var dataLayerException = await Should.ThrowAsync<DataLayerException>(
             async () => await unitOfWork.SaveChangesAsync(TestContext.CancellationToken)
         );

         // Assert
         context.Database.GetDbConnection().State.ShouldBe(ConnectionState.Closed);

-        if (_logger.IsEnabled(LogLevel.Error))
-        {
-            var eventId = Arg.Any<EventId>();
-            var state = Arg.Any<object>();
-            var exception = Arg.Any<Exception>();
-            var formatter = Arg.Any<Func<object, Exception, string>>();
-
-            _logger.Received(1).Log(LogLevel.Error, eventId, state, exception, formatter);
-        }
+        var eventId = Arg.Any<EventId>();
+        var state = Arg.Any<object>();
+        var exception = Arg.Any<Exception>();
+        var formatter = Arg.Any<Func<object, Exception, string>>();
+
+        _logger.Received(1).Log(LogLevel.Error, eventId, state, exception, formatter);

         _ = dataLayerException.ShouldNotBeNull();

Nota: Se este padrão de verificação condicional faz parte de uma convenção estabelecida no projeto para manter consistência com o código de produção, desconsidere esta sugestão.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cd86ef and 9684bb3.

📒 Files selected for processing (52)
  • .github/workflows/workflow-ci.yml (1 hunks)
  • Directory.Build.props (1 hunks)
  • Directory.Packages.props (1 hunks)
  • InvoiceReminder.API.UnitTests/AuthenticationSetup/BearerSecuritySchemeTransformerTests.cs (1 hunks)
  • InvoiceReminder.API.UnitTests/Endpoints/LoginEndpointTests.cs (1 hunks)
  • InvoiceReminder.API.UnitTests/InvoiceReminder.API.UnitTests.csproj (1 hunks)
  • InvoiceReminder.API/AuthenticationSetup/BearerSecuritySchemeTransformer.cs (2 hunks)
  • InvoiceReminder.API/Dockerfile (1 hunks)
  • InvoiceReminder.API/InvoiceReminder.API.csproj (1 hunks)
  • InvoiceReminder.API/InvoiceReminder.http (1 hunks)
  • InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs (1 hunks)
  • InvoiceReminder.Application.UnitTests/InvoiceReminder.Application.UnitTests.csproj (1 hunks)
  • InvoiceReminder.Application/InvoiceReminder.Application.csproj (0 hunks)
  • InvoiceReminder.Application/ViewModels/UserViewModel.cs (1 hunks)
  • InvoiceReminder.ArchitectureTests/InvoiceReminder.ArchitectureTests.csproj (1 hunks)
  • InvoiceReminder.Authentication/InvoiceReminder.Authentication.csproj (0 hunks)
  • InvoiceReminder.CrossCutting.IoC/InvoiceReminder.CrossCutting.IoC.csproj (0 hunks)
  • InvoiceReminder.Data/InvoiceReminder.Data.csproj (1 hunks)
  • InvoiceReminder.Data/Repository/BaseRepository.cs (1 hunks)
  • InvoiceReminder.Data/Repository/EmailAuthTokenRepository.cs (3 hunks)
  • InvoiceReminder.Data/Repository/InvoiceRepository.cs (3 hunks)
  • InvoiceReminder.Data/Repository/JobScheduleRepository.cs (3 hunks)
  • InvoiceReminder.Data/Repository/ScanEmailDefinitionRepository.cs (7 hunks)
  • InvoiceReminder.Data/Repository/UnitOfWork.cs (1 hunks)
  • InvoiceReminder.Data/Repository/UserRepository.cs (5 hunks)
  • InvoiceReminder.Domain/Entities/User.cs (1 hunks)
  • InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1 hunks)
  • InvoiceReminder.Domain/Extensions/UserExtensions.cs (1 hunks)
  • InvoiceReminder.Domain/InvoiceReminder.Domain.csproj (0 hunks)
  • InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs (1 hunks)
  • InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs (2 hunks)
  • InvoiceReminder.DomainEntities.UnitTests/InvoiceReminder.DomainEntities.UnitTests.csproj (1 hunks)
  • InvoiceReminder.ExternalServices.UnitTests/BarcodeReader/BarcodeReaderServiceTests.cs (1 hunks)
  • InvoiceReminder.ExternalServices.UnitTests/InvoiceReminder.ExternalServices.UnitTests.csproj (1 hunks)
  • InvoiceReminder.ExternalServices.UnitTests/SendMessage/SendMessageServiceTests.cs (3 hunks)
  • InvoiceReminder.ExternalServices/BackgroundServices/TelegramBotBackgroundService.cs (1 hunks)
  • InvoiceReminder.ExternalServices/BarcodeReader/BarcodeReaderService.cs (1 hunks)
  • InvoiceReminder.ExternalServices/Gmail/GoogleOAuthService.cs (4 hunks)
  • InvoiceReminder.ExternalServices/InvoiceReminder.ExternalServices.csproj (0 hunks)
  • InvoiceReminder.ExternalServices/SendMessage/SendMessageService.cs (4 hunks)
  • InvoiceReminder.ExternalServices/Telegram/TelegramMessageService.cs (1 hunks)
  • InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs (1 hunks)
  • InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UnitOfWorkTests.cs (3 hunks)
  • InvoiceReminder.Infrastructure.UnitTests/InvoiceReminder.Infrastructure.UnitTests.csproj (1 hunks)
  • InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs (2 hunks)
  • InvoiceReminder.JobScheduler.UnitTests/InvoiceReminder.JobScheduler.UnitTests.csproj (1 hunks)
  • InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (4 hunks)
  • InvoiceReminder.JobScheduler/HostedService/QuartzHostedService.cs (1 hunks)
  • InvoiceReminder.JobScheduler/InvoiceReminder.JobScheduler.csproj (0 hunks)
  • InvoiceReminder.JobScheduler/JobSettings/CronJob.cs (1 hunks)
  • InvoiceReminder.UnitTests.Assets/InvoiceReminder.UnitTests.Assets.csproj (0 hunks)
  • InvoiceReminder.sln (2 hunks)
💤 Files with no reviewable changes (7)
  • InvoiceReminder.JobScheduler/InvoiceReminder.JobScheduler.csproj
  • InvoiceReminder.Domain/InvoiceReminder.Domain.csproj
  • InvoiceReminder.Application/InvoiceReminder.Application.csproj
  • InvoiceReminder.UnitTests.Assets/InvoiceReminder.UnitTests.Assets.csproj
  • InvoiceReminder.ExternalServices/InvoiceReminder.ExternalServices.csproj
  • InvoiceReminder.CrossCutting.IoC/InvoiceReminder.CrossCutting.IoC.csproj
  • InvoiceReminder.Authentication/InvoiceReminder.Authentication.csproj
🧰 Additional context used
🧬 Code graph analysis (5)
InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs (1)
InvoiceReminder.JobScheduler/HostedService/QuartzHostedService.cs (2)
  • IJobDetail (157-170)
  • ITrigger (146-155)
InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs (2)
InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1)
  • Guid (18-21)
InvoiceReminder.Domain/Entities/User.cs (2)
  • User (3-21)
  • User (14-20)
InvoiceReminder.Domain/Extensions/UserExtensions.cs (4)
InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1)
  • AddIfNotExists (5-16)
InvoiceReminder.Domain/Entities/JobSchedule.cs (1)
  • JobSchedule (3-7)
InvoiceReminder.Domain/Entities/EmailAuthToken.cs (1)
  • EmailAuthToken (3-12)
InvoiceReminder.Domain/Entities/ScanEmailDefinition.cs (1)
  • ScanEmailDefinition (5-13)
InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs (1)
InvoiceReminder.Domain/Extensions/EntityExtensions.cs (2)
  • Guid (18-21)
  • AddIfNotExists (5-16)
InvoiceReminder.ExternalServices/Gmail/GoogleOAuthService.cs (1)
InvoiceReminder.Domain/Services/Configuration/ConfigurationService.cs (3)
  • GetSecret (40-43)
  • GetSecret (45-48)
  • GetSecret (50-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (43)
InvoiceReminder.ExternalServices.UnitTests/BarcodeReader/BarcodeReaderServiceTests.cs (1)

14-14: Classe de teste sealed está ok

Marcar a classe de teste como sealed aqui é seguro e não afeta o comportamento dos testes, já que ela não é usada como base para outras classes. Ajudará a evitar herança acidental no futuro.

InvoiceReminder.ExternalServices/BackgroundServices/TelegramBotBackgroundService.cs (1)

98-116: Guard de logging de erro está consistente e preserva o comportamento

A adição de _logger.IsEnabled(LogLevel.Error) em ambos os caminhos de erro mantém o fluxo original e apenas evita o custo do log quando o nível Error estiver desabilitado, alinhando com o padrão do PR. As mensagens e placeholders ({ErrorCode}, {Message}) estão corretos e usam o ApiRequestException apropriadamente.

InvoiceReminder.Application/ViewModels/UserViewModel.cs (1)

29-31: LGTM! Inicialização defensiva das coleções.

A inicialização das coleções no construtor previne NullReferenceException e está alinhada com as mudanças na entidade de domínio User.

InvoiceReminder.Domain/Entities/User.cs (1)

14-20: LGTM! Inicialização adequada das coleções de navegação.

O construtor inicializa todas as propriedades de coleção para arrays vazios, prevenindo NullReferenceException e garantindo que as coleções sempre estejam prontas para uso. Essa é uma prática recomendada para entidades com relacionamentos de navegação.

InvoiceReminder.Domain/Extensions/UserExtensions.cs (1)

14-17: Refatoração positiva, mas dependente das correções em EntityExtensions.

A substituição da lógica manual por chamadas AddIfNotExists torna o código mais limpo e reduz duplicação. No entanto, este código herda os problemas de desempenho e segurança identificados em EntityExtensions.AddIfNotExists.

Certifique-se de aplicar as correções sugeridas no arquivo InvoiceReminder.Domain/Extensions/EntityExtensions.cs antes de fazer merge desta PR.

Por favor, confirme que as correções críticas de segurança e as otimizações de desempenho em EntityExtensions serão aplicadas.

Also applies to: 23-26

InvoiceReminder.DomainEntities.UnitTests/Extensions/EntityExtensionsTests.cs (1)

1-236: Excelente cobertura de testes para a nova extensão AddIfNotExists!

A suíte de testes é abrangente e cobre adequadamente:

  • ✓ Cenários de borda (entidade nula, GUID vazio)
  • ✓ Prevenção de duplicatas baseada em Id
  • ✓ Compatibilidade com diferentes tipos de coleção (List, HashSet)
  • ✓ Preservação de entidades existentes
  • ✓ Múltiplas chamadas com a mesma entidade

Os testes estão bem estruturados com padrão AAA (Arrange-Act-Assert) e usam asserções claras do Shouldly.

InvoiceReminder.DomainEntities.UnitTests/Extensions/UserExtensionsTests.cs (3)

8-8: Bom uso do modificador sealed na classe de teste.

Marcar a classe de teste como sealed é uma boa prática que pode proporcionar pequenas melhorias de desempenho e deixa claro que a classe não foi projetada para ser herdada.


438-438: Renomeação apropriada do método de teste.

O nome Handle_NewUserWithEmptyCollections_InitializesCollections reflete mais precisamente o comportamento atual, já que o construtor de User agora inicializa as coleções como vazias (não nulas).


445-445: Remoção correta de inicializações redundantes.

A remoção das inicializações explícitas está alinhada com o fato de que o construtor de User agora inicializa todas as coleções automaticamente. O teste continua validando o comportamento correto.

InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs (1)

12-12: LGTM! Classe de teste selada adequadamente.

Selar classes de teste é uma boa prática quando não há intenção de herança, melhorando a clareza do design.

InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (1)

12-12: LGTM! Classe de teste selada adequadamente.

Selar a classe de teste segue as boas práticas quando não há necessidade de herança.

InvoiceReminder.API/AuthenticationSetup/BearerSecuritySchemeTransformer.cs (1)

38-41: Atribuição de SecuritySchemes compatível com a nova API

O uso de ToDictionary com cast explícito para IOpenApiSecurityScheme deixa a atribuição aderente ao novo tipo da propriedade e mantém o comportamento anterior (apenas esquema Bearer definido). Não vejo riscos aqui.

InvoiceReminder.Application.UnitTests/AppServices/BaseAppServiceTests.cs (1)

9-10: Selar a classe de teste é adequado

Deixar BaseAppServiceTests como sealed explicita que não deve ser herdada e está alinhado com o padrão adotado nas demais classes de teste do PR. Nenhum impacto funcional.

InvoiceReminder.Infrastructure.UnitTests/Data/Repository/BaseRepositoryTests.cs (1)

10-12: Classe de teste selada de forma consistente

Tornar BaseRepositoryTests sealed é coerente com o restante da suíte de testes e deixa claro que ela não deve ser estendida. Nenhum problema identificado.

InvoiceReminder.API/InvoiceReminder.http (1)

3-361: Arquivo .http bem completo e organizado

Gostei bastante da expansão do InvoiceReminder.http: os blocos separados por contexto (LOGIN, USER, INVOICE, JOB SCHEDULE, SCAN EMAIL, GOOGLE OAUTH) com exemplos de payloads e cabeçalhos facilitam muito o uso da API durante o desenvolvimento. A padronização de Authorization: Bearer your_jwt_token_here e o uso de GUIDs de exemplo tornam o arquivo seguro e autoexplicativo.

InvoiceReminder.DomainEntities.UnitTests/InvoiceReminder.DomainEntities.UnitTests.csproj (1)

8-10: Configuração do MSTest Runner está correta.

A configuração do projeto de testes está alinhada com as práticas recomendadas do MSTest para .NET 10, utilizando o runner nativo ao invés do VSTest.

InvoiceReminder.ExternalServices.UnitTests/InvoiceReminder.ExternalServices.UnitTests.csproj (1)

8-10: Configuração consistente com os demais projetos de teste.

A configuração do runner MSTest está alinhada com os outros projetos de teste da solução.

InvoiceReminder.ExternalServices/Gmail/GoogleOAuthService.cs (2)

24-24: Boa refatoração com a constante AppKeysSection.

A introdução da constante AppKeysSection melhora a manutenibilidade e segue o princípio DRY, evitando strings duplicadas.


116-119: Logging guardado aplicado corretamente.

A verificação IsEnabled(LogLevel.Error) antes do log evita alocações desnecessárias quando o nível de log não está habilitado.

InvoiceReminder.ExternalServices/SendMessage/SendMessageService.cs (3)

18-18: Boa padronização do formato de mensagem de log.

A constante LogExceptionMessage padroniza o formato das mensagens de exceção, facilitando a análise de logs.


83-86: Logging guardado aplicado corretamente para OperationCanceledException.

O padrão de verificação IsEnabled antes do log está implementado corretamente.


113-116: Logging guardado aplicado corretamente em ValidateUser.

InvoiceReminder.ExternalServices.UnitTests/SendMessage/SendMessageServiceTests.cs (1)

15-15: Boa prática: classe de teste selada.

Marcar classes de teste como sealed é uma boa prática que melhora a performance e deixa claro que a classe não deve ser herdada.

Directory.Packages.props (2)

46-46: Nota sobre Z.EntityFramework.Extensions.EFCore.

Este é um pacote comercial que substitui o EFCore.BulkExtensions. Certifique-se de que a licença está em conformidade com os requisitos do projeto.


15-46: Migração de pacotes para .NET 10 bem estruturada.

A organização dos pacotes em grupos rotulados ("System Packages", "Unit Tests Packages") e a centralização das versões facilita a manutenção. A migração para versões 10.0.0 está consistente.

InvoiceReminder.API.UnitTests/AuthenticationSetup/BearerSecuritySchemeTransformerTests.cs (1)

4-4: Alinhamento de namespace do OpenAPI

A troca para using Microsoft.OpenApi; está consistente com as mudanças na classe de produção e não altera o comportamento dos testes. Nada a ajustar aqui.

InvoiceReminder.Data/Repository/BaseRepository.cs (1)

28-39: Uso do CancellationToken em BulkInsertAsync

A atualização para passar o cancellationToken de forma posicional em BulkInsertAsync mantém a intenção original de propagar cancelamento para a operação em lote. A lógica de timestamp continua intacta. 👍

InvoiceReminder.Data/Repository/InvoiceRepository.cs (1)

16-17: Padronização e guarda dos logs de exceção

Boa melhoria ao introduzir LogExceptionMessage e envolver os LogWarning/LogError em checagens de IsEnabled. Isso padroniza o formato de mensagem e evita trabalho de logging desnecessário quando o nível correspondente estiver desativado, mantendo o fluxo de exceção inalterado.

Also applies to: 40-55

InvoiceReminder.sln (1)

3-4: Atualização de versão da Solution e inclusão do Directory.Build.props

A atualização do cabeçalho para Visual Studio 18 e a adição de Directory.Build.props em Solution Items são mudanças administrativas que não impactam o build e facilitam a descoberta da configuração global. Tudo certo aqui.

Also applies to: 65-65

InvoiceReminder.Data/Repository/UnitOfWork.cs (1)

39-42: Guarda de log de erro no SaveChangesAsync

O uso de _logger.IsEnabled(LogLevel.Error) antes do LogError está alinhado com o padrão aplicado nos demais repositórios e não altera o fluxo de transação/rollback. Implementação está ok.

InvoiceReminder.JobScheduler/JobSettings/CronJob.cs (1)

28-31: Guard de LogInformation no job de cron

A checagem de _logger.IsEnabled(LogLevel.Information) antes de logar a mensagem deixa o job consistente com o restante da solução e evita logs quando o nível Info estiver desligado. Nada a ajustar aqui.

InvoiceReminder.API.UnitTests/Endpoints/LoginEndpointTests.cs (1)

21-21: Classe de teste selada

Marcar LoginEndpointTests como sealed é compatível com MSTest e evita herança acidental em testes. Mudança simples e bem-vinda.

Directory.Build.props (1)

1-10: Centralização de propriedades de build é correta

A centralização de TargetFramework, LangVersion, ImplicitUsings e TieredPGO em Directory.Build.props é uma abordagem adequada e simplifica a manutenção.

Quanto aos pontos levantados na revisão anterior:

  • <Nullable>disable</Nullable>: Nenhum .csproj individual possui override para esta propriedade, indicando que a configuração global é intencional e consistente com o estado atual do código.

  • <UserSecretsId> na raiz: Não existem configurações de UserSecretsId em projetos individuais. Em uma arquitetura típica, apenas projetos web (como InvoiceReminder.API) utilizariam secrets, enquanto projetos de biblioteca (Domain, Data, Infrastructure, etc.) herdando esta propriedade não a utilizam. Logo, não há risco de mistura de segredos entre projetos.

A configuração está funcional e sem conflitos.

Likely an incorrect or invalid review comment.

InvoiceReminder.JobScheduler.UnitTests/InvoiceReminder.JobScheduler.UnitTests.csproj (1)

8-10: Configuração do runner de testes está coerente

As propriedades EnableMSTestRunner, OutputType e UseVSTest estão alinhadas com a estratégia de executar os testes como executáveis e centralizar a configuração em Directory.Build.props. Nada a ajustar aqui, só garantir que o pipeline/IDE está realmente usando esse modelo em todos os projetos de teste.

InvoiceReminder.Application.UnitTests/InvoiceReminder.Application.UnitTests.csproj (1)

8-10: Consistência de configuração entre projetos de teste

Este projeto segue o mesmo padrão de runner de teste (EnableMSTestRunner/OutputType/UseVSTest) dos demais, o que simplifica bastante manutenção e execução dos testes na solução. Nenhum ajuste necessário aqui.

InvoiceReminder.API.UnitTests/InvoiceReminder.API.UnitTests.csproj (1)

8-10: Projeto de testes de API alinhado com o novo modelo de execução

As propriedades do runner (EnableMSTestRunner, OutputType, UseVSTest) estão em linha com os demais projetos de teste, o que facilita a execução unificada no CI e localmente. Tudo ok aqui.

InvoiceReminder.Data/Repository/JobScheduleRepository.cs (1)

16-16: Tratamento de erros de JobSchedule agora segue o padrão comum

O repositório de JobSchedule passou a usar o mesmo template de log e os checks de IsEnabled para warnings/erros que os demais repositórios, mantendo o contexto na mensagem e preservando o comportamento de exceção (OperationCanceledException em cancelamento e DataLayerException nos demais erros). A padronização ajuda bastante na observabilidade.

Also applies to: 40-43, 52-55

InvoiceReminder.Infrastructure.UnitTests/InvoiceReminder.Infrastructure.UnitTests.csproj (1)

8-10: Projeto de testes de infraestrutura configurado de forma consistente

A adoção do mesmo conjunto de propriedades de execução de testes que o resto da solução evita surpresas (especialmente com EF Core e dependências de infraestrutura). Configuração parece correta e homogênea.

InvoiceReminder.ArchitectureTests/InvoiceReminder.ArchitectureTests.csproj (1)

8-10: LGTM! Configuração moderna do MSTest runner.

A configuração do novo MSTest runner está alinhada com o MSTest.Sdk 4.0.2 e é consistente com a execução de testes baseada em executáveis implementada no workflow de CI.

InvoiceReminder.Data/InvoiceReminder.Data.csproj (2)

14-14: Verifique se a remoção de contentfiles não afeta as ferramentas de design do EF Core.

A remoção de contentfiles dos IncludeAssets do pacote Microsoft.EntityFrameworkCore.Design pode afetar templates de scaffolding e outras funcionalidades de design-time. Confirme que comandos como dotnet ef migrations add e dotnet ef dbcontext scaffold ainda funcionam corretamente.


9-9: No critical issues found with the library migration to Z.EntityFramework.Extensions.EFCore.

The replacement from EFCore.BulkExtensions to Z.EntityFramework.Extensions.EFCore is already in place and working correctly. The BulkInsertAsync extension method is being used properly throughout the codebase (BaseRepository, SendMessageService, and tests), and the lack of explicit using statements is expected since Z.EntityFramework.Extensions adds extension methods to DbContext that are automatically available when the NuGet package is referenced.

Note: Z.EntityFramework.Extensions.EFCore is a commercial library. Ensure your organization has the appropriate licensing.

.github/workflows/workflow-ci.yml (1)

23-29: LGTM! Atualização para .NET 10 e configuração de build apropriada.

A atualização para .NET 10.0.x e o uso explícito de --configuration Debug estão corretos para o pipeline de CI.

InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UnitOfWorkTests.cs (1)

15-15: LGTM! Uso correto de sealed em classe de teste.

Marcar a classe de teste como sealed é uma boa prática, pois classes de teste geralmente não precisam de herança.

Comment thread .github/workflows/workflow-ci.yml
Comment thread Directory.Packages.props
Comment thread InvoiceReminder.Domain/Extensions/EntityExtensions.cs
Comment thread InvoiceReminder.Domain/Extensions/EntityExtensions.cs Outdated
Comment thread InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs Outdated
Simplifies unit tests by removing redundant checks for logger enablement.
This streamlines the tests and makes them more readable without affecting their functionality.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1)

19-22: Otimização de performance não aplicada.

O comentário anterior sugeriu cachear GetId(entity) fora do lambda para evitar recalcular para cada elemento. Essa otimização ainda não foi aplicada.

+var entityId = EntityIdComparer<T>.GetId(entity);
-if (collection.FirstOrDefault(e => EntityIdComparer<T>.GetId(e).Equals(EntityIdComparer<T>.GetId(entity))) is null)
+if (!collection.Any(e => EntityIdComparer<T>.GetId(e).Equals(entityId)))
 {
     collection.Add(entity);
 }
🧹 Nitpick comments (4)
InvoiceReminder.ExternalServices.UnitTests/SendMessage/SendMessageServiceTests.cs (1)

115-127: Aprovo a refatoração da verificação de logs, mas considere verificar a exceção específica.

A adição do mock IsEnabled e a refatoração da verificação de logs para usar argumentos explícitos torna o teste mais claro. No entanto, na linha 124, Arg.Any<Exception>() aceita qualquer exceção ao invés de verificar que a exceção logada é a mesma que foi lançada.

Considere aplicar este diff para verificar a exceção específica:

-        var loggedException = Arg.Any<Exception>();
+        var loggedException = Arg.Is<Exception>(e => e == exception);
InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (1)

108-113: Considere simplificar a verificação de exceção nula.

A verificação Arg.Is<Exception>(e => e == null) na linha 110 funciona corretamente, mas pode ser simplificada passando diretamente null ou usando Arg.Is<Exception>(e => e is null) para maior clareza.

Aplique esta alteração para simplificar:

-        var loggedException = Arg.Is<Exception>(e => e == null);
+        var loggedException = null as Exception;

Ou alternativamente:

-        var loggedException = Arg.Is<Exception>(e => e == null);
+        var loggedException = Arg.Is<Exception>(e => e is null);
InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1)

26-36: Implementação de IEqualityComparer<T> não utilizada.

A classe EntityIdComparer<T> implementa IEqualityComparer<T>, mas apenas o método estático GetId é utilizado. Os métodos Equals e GetHashCode da interface nunca são chamados.

Se a intenção era otimizar o HashSet com comparação por Id, o comparador deveria ser passado na construção do HashSet. Caso contrário, considere simplificar a classe.

Opção 1 - Simplificar removendo a interface não utilizada:

-internal sealed class EntityIdComparer<T> : IEqualityComparer<T> where T : class
+internal static class EntityIdHelper<T> where T : class
 {
-    public bool Equals(T x, T y)
-    {
-        return !(x == null || y == null) && GetId(x).Equals(GetId(y));
-    }
-
-    public int GetHashCode(T obj)
-    {
-        return obj == null ? 0 : GetId(obj).GetHashCode();
-    }
-
     public static Guid GetId(T entity)
     {
         // ... implementation unchanged
     }
 }

Opção 2 - Usar o comparador no HashSet (requer mudança na chamada):

var hashSetWithComparer = new HashSet<T>(new EntityIdComparer<T>());
InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UnitOfWorkTests.cs (1)

69-90: Use inline Arg.Any<T>() in log verification and consider isolating mock state between tests

The test correctly verifies that an error log occurs on exception, but the verification pattern can be improved:

  1. Use inline Arg.Any() matchers (best practice)
    NSubstitute documentation recommends using argument matchers directly at the call site rather than in local variables. Replace lines 84–89 with:

  •        var eventId = Arg.Any<EventId>();
    
  •        var state = Arg.Any<object>();
    
  •        var exception = Arg.Any<Exception>();
    
  •        var formatter = Arg.Any<Func<object, Exception, string>>();
    
  •        _logger.Received(1).Log(LogLevel.Error, eventId, state, exception, formatter);
    
  •        _logger.Received(1).Log(
    
  •            LogLevel.Error,
    
  •            Arg.Any<EventId>(),
    
  •            Arg.Any<object>(),
    
  •            Arg.Any<Exception>(),
    
  •            Arg.Any<Func<object, Exception, string>>());
    
    
    
  1. Prevent mock state fragility (optional)
    The _logger is created in the constructor and shared across all tests. Currently only one test verifies logging, but future tests that log errors will cause Received(1) to fail. Either recreate the mock in [TestInitialize] or call _logger.ClearReceivedCalls(); at the start of each logging-verification test to ensure count accuracy.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9684bb3 and b392e76.

📒 Files selected for processing (5)
  • InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1 hunks)
  • InvoiceReminder.ExternalServices.UnitTests/SendMessage/SendMessageServiceTests.cs (3 hunks)
  • InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UnitOfWorkTests.cs (3 hunks)
  • InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs (2 hunks)
  • InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • InvoiceReminder.JobScheduler.UnitTests/HostedService/QuartzHostedServiceTests.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (7)
InvoiceReminder.ExternalServices.UnitTests/SendMessage/SendMessageServiceTests.cs (2)

15-15: LGTM! Boa prática tornar a classe de testes sealed.

Tornar a classe de testes sealed é uma boa prática que previne herança desnecessária e deixa clara a intenção de que esta é uma classe final.


147-160: LGTM! Refatoração melhora a clareza da verificação de logs.

A adição do mock IsEnabled e a refatoração da verificação de logs usando argumentos explícitos torna o teste mais claro e legível. A verificação de que a exceção é null (linha 157) está correta para o cenário de warning.

InvoiceReminder.JobScheduler.UnitTests/JobSettings/CronJobTests.cs (3)

12-12: Boa prática: classe de teste selada.

Marcar a classe de teste como sealed é uma boa prática que previne herança acidental e pode proporcionar pequenos ganhos de performance.


52-52: Configuração correta para logging protegido.

A configuração do mock _logger.IsEnabled(...) retornando true é necessária para permitir que o código de logging protegido execute durante os testes, possibilitando as verificações de log subsequentes.

Also applies to: 99-99


62-66: Verifique a consistência das asserções de logging.

Este teste usa ReceivedWithAnyArgs para verificar o logging sem validar o conteúdo da mensagem, enquanto o teste Execute_SendMessageFails_ShouldNotThrowExceptionAndStillLog (linhas 108-113) usa Received(1) com validação específica do conteúdo. Se a intenção é apenas verificar que o log foi chamado sem importar a mensagem, a abordagem está correta. Caso contrário, considere alinhar ambas as asserções para maior consistência.

InvoiceReminder.Domain/Extensions/EntityExtensions.cs (1)

38-49: Implementação segura do GetId.

A validação adequada foi adicionada para tratar casos onde a propriedade Id não existe, é nula, ou não é do tipo Guid. Isso resolve a preocupação de segurança levantada anteriormente.

InvoiceReminder.Infrastructure.UnitTests/Data/Repository/UnitOfWorkTests.cs (1)

15-15: Classe de teste sealed é uma boa escolha aqui

Marcar a classe de teste como sealed é coerente com o padrão do PR, evita herança acidental e não traz impacto negativo para os testes.

Comment thread InvoiceReminder.Domain/Extensions/EntityExtensions.cs
Ensures that duplicate entities are not added to collections
by checking for existing entities with the same ID.

This prevents potential data integrity issues and improves the
reliability of the application when dealing with collections
of entities.
@jldsilva jldsilva merged commit 5ebd98a into development Dec 5, 2025
4 checks passed
@jldsilva jldsilva deleted the dotNet10-Update branch December 5, 2025 02:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant