Skip to content

feat(data)!: implement Repository pattern #189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 30, 2025

Conversation

nanotaboada
Copy link
Owner

@nanotaboada nanotaboada commented Mar 30, 2025

Summary by CodeRabbit

  • New Features

    • Implemented a repository abstraction to improve data management and standardize CRUD operations.
    • Enhanced service registration to streamline dependency injection and caching.
  • Tests

    • Consolidated and standardized the unit testing suite, adding comprehensive new tests for critical functionality and performance.
    • Removed outdated test files and reorganized test classes for better structure.
  • Refactor

    • Transitioned service data access to the repository pattern with updated documentation terminology.
    • Reorganized testing utilities and namespaces for improved clarity and maintainability.
  • Chores

    • Upgraded external API documentation and UI dependencies to the latest supported versions.

Copy link

coderabbitai bot commented Mar 30, 2025

Walkthrough

The changes reorganize and refactor the codebase for testing and data access. A redundant test file was removed, and unit test files were updated with a new namespace and standardized trait attributes. New test classes, especially for the PlayerService, were added with comprehensive CRUD validations using Moq and FluentAssertions. Utility classes for database fakes, mocks, and stubs were introduced or restructured under a dedicated namespace. Additionally, a repository pattern was implemented by adding generic interfaces and classes for managing Player entities, leading to refactoring of PlayerService to use the repository instead of direct DbContext access. Dependency versions were also updated.

Changes

File(s) Change Summary
Dotnet.Samples.AspNetCore.WebApi.Tests/PlayerServiceTests.cs Deleted the file containing comprehensive unit tests for PlayerService.
Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs, Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs Updated namespace to ...Tests.Unit; modified Trait attributes in PlayerControllerTests to a uniform "Unit" category; added a new PlayerServiceTests class with CRUD test methods leveraging Moq and FluentAssertions.
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs, PlayerFakes.cs, PlayerMocks.cs, PlayerStubs.cs Introduced DatabaseFakes for in‑memory SQLite setup; updated namespaces in PlayerFakes, PlayerMocks, and PlayerStubs; added RepositoryMock() in PlayerMocks; removed database setup methods from PlayerStubs, retaining only CreateModelError.
Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json Upgraded Microsoft.OpenApi from 1.6.22 to 1.6.23 and Swashbuckle.AspNetCore (plus related packages) from 7.3.1 to 8.0.0 with updated content hashes and dependency ranges.
Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs, IRepository.cs, PlayerRepository.cs, Repository.cs Introduced a repository pattern with the new generic interface IRepository and specialized IPlayerRepository (including FindBySquadNumberAsync) and their implementations (Repository and PlayerRepository) for standardized asynchronous CRUD operations.
Dotnet.Samples.AspNetCore.WebApi/Program.cs, Services/IPlayerService.cs, Services/PlayerService.cs Updated dependency injection registrations in Program.cs; refactored PlayerService to utilize IPlayerRepository instead of a direct DbContext; modified documentation in IPlayerService to reference the repository.

Sequence Diagram(s)

sequenceDiagram
    participant Ctrl as Controller
    participant PS as PlayerService
    participant Repo as IPlayerRepository
    participant DB as Database

    Ctrl->>PS: Request Operation (Create/Retrieve/Update/Delete)
    PS->>Repo: Invoke corresponding repository method
    Repo->>DB: Execute database operation
    DB-->>Repo: Return result/confirmation
    Repo-->>PS: Send result
    PS-->>Ctrl: Return response
Loading

📜 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 e498f3b and 63b83a6.

📒 Files selected for processing (4)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (15 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerMocks.cs (2 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs (1 hunks)
🧰 Additional context used
🧬 Code Definitions (3)
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerMocks.cs (1)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (1)
  • PlayerService (8-113)
Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (2)
Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (49-49)
  • Task (56-56)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (3)
  • Task (25-29)
  • Task (35-66)
  • Task (78-86)
Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (3)
Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
  • Task (46-46)
Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (49-49)
  • Task (56-56)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (5)
  • Task (25-29)
  • Task (35-66)
  • Task (78-86)
  • Task (92-99)
  • PlayerService (8-113)
🪛 GitHub Check: Codeac Code Quality
Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs

[warning] 45-52: CodeDuplication
This block of 7 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:325


[warning] 325-332: CodeDuplication
This block of 7 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:45

Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs

[warning] 183-194: CodeDuplication
This block of 11 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:110


[warning] 110-121: CodeDuplication
This block of 11 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:183


[warning] 210-218: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:113


[warning] 113-121: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:210

🔇 Additional comments (19)
Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs (2)

11-11: Good alignment with RESTful resource naming conventions.

The class name change from PlayersController to PlayerController follows best practices by using singular nouns for resource types in RESTful APIs. This naming convention is more consistent with the repository pattern being implemented.


15-15: Logger type properly updated to match controller name.

The logger type has been appropriately updated to match the renamed controller class, maintaining consistency throughout the codebase.

Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerMocks.cs (4)

1-10: Appropriate namespaces added with improved organization.

The updated imports and namespace reorganization properly reflect the new project structure using the Repository pattern. Moving the mock utilities to a dedicated namespace improves code organization.


12-18: Excellent documentation added for the Mocks class.

The XML documentation clearly explains the purpose and usage of mocks in testing, which enhances code maintainability and serves as a valuable reference for developers.


21-29: Well-designed mock factory methods for service and repository.

These new methods encapsulate the creation of mocks for IPlayerService and IPlayerRepository, promoting code reuse across test classes and reducing duplication.


63-83: Excellent mock setup helpers with tuple returns.

The SetupServiceMocks and SetupControllerMocks methods provide a clean, reusable way to set up multiple related mocks with a single method call. The use of tuples for return values is a modern C# approach that makes the code more maintainable.

Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (5)

10-12: Good use of namespace restructuring and interface implementation.

Moving the test class to a dedicated Unit namespace improves organization, and implementing IDisposable ensures proper resource cleanup. This follows best practices for test design.


14-19: Proper resource management with environment setup.

Adding a disposal flag and setting up the environment variable in the constructor ensures consistent test execution environment and proper cleanup afterward.


26-26: Good standardization of test categories.

Updating all test traits to use a consistent "Unit" category improves test organization and reporting. This makes it easier to filter and run specific test groups.


30-30: Improved test setup with mock utility methods.

Using the new SetupControllerMocks helper method reduces code duplication and improves readability by centralizing the mock setup logic.


345-358: Proper implementation of the Dispose pattern.

The class correctly implements the standard Dispose pattern with both a public Dispose() method and a protected virtual Dispose(bool) method, ensuring proper resource cleanup and supporting inheritance.

Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (8)

10-17: Good test class setup with environment configuration.

The class implements IDisposable and sets up the necessary environment variable for testing. This ensures consistent test execution and proper cleanup.


23-38: Well-structured test for CreateAsync method.

This test effectively verifies that the CreateAsync method properly delegates to the repository and clears the cache. The arrange-act-assert pattern is clearly followed.


66-87: Excellent performance verification test.

This test verifies an important performance characteristic: that the second retrieval execution should be faster than the first, confirming that caching is working correctly. The custom ExecutionTimeAsync helper method is a good approach.


225-234: Useful helper method for measuring execution time.

The ExecutionTimeAsync method provides a clean way to measure the execution time of async methods, supporting the performance testing needs.


113-126: Consider refactoring duplicate test setup code.

Multiple test methods follow almost identical patterns for setting up mocks, creating services, and performing verifications. This leads to code duplication that could reduce maintainability.

To improve maintainability, consider implementing helper methods for common setup tasks, as suggested in the previous review:

private (Mock<IPlayerRepository> repository, Mock<ILogger<PlayerService>> logger, Mock<IMemoryCache> memoryCache) SetupMocks(object cacheValue = null)
{
    return PlayerMocks.SetupServiceMocks(cacheValue);
}

private PlayerService CreateService(Mock<IPlayerRepository> repository, Mock<ILogger<PlayerService>> logger, Mock<IMemoryCache> memoryCache)
{
    return new PlayerService(repository.Object, logger.Object, memoryCache.Object);
}

This would simplify your test methods:

// Arrange
var player = PlayerFakes.CreateOneByIdFromStarting11(9);
var (repository, logger, memoryCache) = SetupMocks();
repository.Setup(r => r.FindByIdAsync(player.Id)).ReturnsAsync(player);

var service = CreateService(repository, logger, memoryCache);

Also applies to: 183-199, 210-223

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 113-121: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:210


181-199: Test verifies correct update behavior.

This test correctly validates that the UpdateAsync method finds the entity, updates it, and removes the cache entry. The assertions check all critical interactions with dependencies.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 183-194: CodeDuplication
This block of 11 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:110


205-223: Test properly verifies delete operations.

The test for DeleteAsync correctly validates that the method finds the entity, removes it from the repository, and clears the cache. The use of CreateOneNew() instead of retrieving from the starting 11 is a good approach to test with different data.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 210-218: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:113


236-249: Proper implementation of IDisposable pattern.

The Dispose implementation follows best practices with a virtual protected method and proper resource cleanup. The _disposed flag prevents multiple disposals, which is important for robustness.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@nanotaboada nanotaboada force-pushed the feature/repository-pattern branch from f31e753 to e498f3b Compare March 30, 2025 21:17
Copy link

codacy-production bot commented Mar 30, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
-3.16% 78.23%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (2fe760c) 1225 697 56.90%
Head commit (63b83a6) 1258 (+33) 676 (-21) 53.74% (-3.16%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#189) 248 194 78.23%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Copy link

codecov bot commented Mar 30, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (2fe760c) to head (63b83a6).
Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #189   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            2         2           
  Lines          119       111    -8     
  Branches         7         7           
=========================================
- Hits           119       111    -8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (13)
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerStubs.cs (1)

1-5: Clean up unnecessary using directives.

Now that the database-related methods have been moved to DatabaseFakes, several using directives are no longer needed in this file:

  • System.Data.Common
  • Dotnet.Samples.AspNetCore.WebApi.Data
  • Microsoft.Data.Sqlite
  • Microsoft.EntityFrameworkCore

Only Microsoft.AspNetCore.Mvc.ModelBinding is required for the current functionality.

-using System.Data.Common;
-using Dotnet.Samples.AspNetCore.WebApi.Data;
using Microsoft.AspNetCore.Mvc.ModelBinding;
-using Microsoft.Data.Sqlite;
-using Microsoft.EntityFrameworkCore;
Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1)

10-11: Consider adding cancellation token support.

To improve the robustness of async operations, especially for long-running queries in production environments, consider adding cancellation token support.

-public async ValueTask<Player?> FindBySquadNumberAsync(int squadNumber) =>
-    await _dbSet.FirstOrDefaultAsync(p => p.SquadNumber == squadNumber);
+public async ValueTask<Player?> FindBySquadNumberAsync(int squadNumber, CancellationToken cancellationToken = default) =>
+    await _dbSet.FirstOrDefaultAsync(p => p.SquadNumber == squadNumber, cancellationToken);
Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (2)

15-46: Consider adding cancellation tokens to async methods.

For all asynchronous methods, it's a best practice to include optional cancellation token parameters to allow for cancellation of long-running operations, especially in web applications.

-Task AddAsync(T entity);
+Task AddAsync(T entity, CancellationToken cancellationToken = default);

-Task<List<T>> GetAllAsync();
+Task<List<T>> GetAllAsync(CancellationToken cancellationToken = default);

-ValueTask<T?> FindByIdAsync(long id);
+ValueTask<T?> FindByIdAsync(long id, CancellationToken cancellationToken = default);

-Task UpdateAsync(T entity);
+Task UpdateAsync(T entity, CancellationToken cancellationToken = default);

-Task RemoveAsync(long id);
+Task RemoveAsync(long id, CancellationToken cancellationToken = default);

10-46: Consider adding transaction support.

For operations that may require transactional integrity, especially when multiple operations need to be performed as a single unit of work, consider adding transaction support methods.

+/// <summary>
+/// Begins a new transaction.
+/// </summary>
+/// <returns>A Task representing the transaction.</returns>
+Task<IDbContextTransaction> BeginTransactionAsync(CancellationToken cancellationToken = default);

+/// <summary>
+/// Saves all pending changes in the context.
+/// </summary>
+/// <returns>A Task representing the save operation with the number of entities written.</returns>
+Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (2)

12-20: Consider adding cancellation token to the specialized method.

For consistency with other async methods, consider adding a cancellation token parameter to the FindBySquadNumberAsync method.

-ValueTask<Player?> FindBySquadNumberAsync(int squadNumber);
+ValueTask<Player?> FindBySquadNumberAsync(int squadNumber, CancellationToken cancellationToken = default);

1-2: Remove unnecessary file header comment.

The first line contains a comment with the filename which is redundant since the filename is already known from the file itself. Consider removing this comment to maintain cleaner code.

-// IPlayerRepository.cs
-
 using Dotnet.Samples.AspNetCore.WebApi.Models;
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerMocks.cs (1)

19-24: The RepositoryMock method is correctly implemented but lacks setup for common repository operations.

While the method successfully creates a mock of IPlayerRepository, it doesn't include any default setup for common operations that might be needed in multiple tests.

Consider enhancing this method with common setups that can be reused across tests, similar to how MemoryCacheMock is implemented:

public static Mock<IPlayerRepository> RepositoryMock()
{
    var mock = new Mock<IPlayerRepository>();
+    
+    // Setup common operations
+    mock.Setup(repo => repo.GetAllAsync())
+        .ReturnsAsync(new List<Player>());
+    
+    mock.Setup(repo => repo.FindByIdAsync(It.IsAny<long>()))
+        .Returns((long id) => ValueTask.FromResult<Player?>(null));

    return mock;
}
Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (4)

17-21: Consider adding transaction handling for the AddAsync method.

The current implementation makes two separate database calls (Add and SaveChanges) without transaction handling.

Consider adding transaction handling for operations that involve multiple database calls:

public async Task AddAsync(T entity)
{
+    using var transaction = await _dbContext.Database.BeginTransactionAsync();
+    try
+    {
        await _dbSet.AddAsync(entity);
        await _dbContext.SaveChangesAsync();
+        await transaction.CommitAsync();
+    }
+    catch
+    {
+        await transaction.RollbackAsync();
+        throw;
+    }
}

25-25: FindByIdAsync lacks NoTracking option for read-only scenarios.

When retrieving entities for read-only purposes, using AsNoTracking can improve performance.

Consider providing an overload that supports NoTracking:

public async ValueTask<T?> FindByIdAsync(long id) => await _dbSet.FindAsync(id);

+public async ValueTask<T?> FindByIdNoTrackingAsync(long id)
+{
+    return await _dbSet.AsNoTracking().FirstOrDefaultAsync(e => EF.Property<long>(e, "Id") == id);
+}

27-31: Consider adding transaction handling for the UpdateAsync method.

Similar to AddAsync, this method performs multiple database operations without transaction handling.

Consider adding transaction handling as suggested for the AddAsync method.


33-41: RemoveAsync method could be optimized for performance.

The current implementation makes an extra database call to find the entity before removing it.

For better performance with bulk operations, consider using a direct removal approach:

public async Task RemoveAsync(long id)
{
-    var entity = await _dbSet.FindAsync(id);
-    if (entity != null)
-    {
-        _dbSet.Remove(entity);
-        await _dbContext.SaveChangesAsync();
-    }
+    // Create a proxy entity with just the ID
+    var entityType = _dbContext.Model.FindEntityType(typeof(T));
+    var entity = Activator.CreateInstance<T>();
+    entityType?.FindPrimaryKey()?.Properties
+        .Single()
+        .PropertyInfo?
+        .SetValue(entity, id);
+
+    _dbContext.Entry(entity).State = EntityState.Deleted;
+    await _dbContext.SaveChangesAsync();
}

Alternatively, provide both approaches as separate methods for different use cases.

Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs (1)

36-47: Schema maintenance caution
Manual SQL table creation may drift out of sync if the EF model evolves. Consider using EF Core migrations or EnsureCreated() to maintain consistency and reduce maintenance overhead.

Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (1)

221-241: Consider using Times.Once() for consistency.

The test for DeleteAsync is well-structured, but line 240 uses Times.Exactly(1) while other tests use Times.Once(). Consider standardizing verification syntax across tests.

-        memoryCache.Verify(cache => cache.Remove(It.IsAny<object>()), Times.Exactly(1));
+        memoryCache.Verify(cache => cache.Remove(It.IsAny<object>()), Times.Once());
🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 226-236: CodeDuplication
This block of 10 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:121

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2fe760c and e498f3b.

📒 Files selected for processing (15)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/PlayerServiceTests.cs (0 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (15 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerMocks.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerStubs.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json (3 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Program.cs (1 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (3 hunks)
  • Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (5 hunks)
💤 Files with no reviewable changes (1)
  • Dotnet.Samples.AspNetCore.WebApi.Tests/PlayerServiceTests.cs
🧰 Additional context used
🧬 Code Definitions (6)
Dotnet.Samples.AspNetCore.WebApi/Program.cs (2)
Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1)
  • PlayerRepository (6-12)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (1)
  • PlayerService (8-113)
Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (1)
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (1)
  • List (37-193)
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs (1)
Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (1)
  • PlayerFakes (14-194)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (4)
Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)
  • ValueTask (20-20)
Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (5)
  • ValueTask (32-32)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
  • Task (46-46)
Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1)
  • ValueTask (10-11)
Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (5)
  • ValueTask (25-25)
  • Task (17-21)
  • Task (23-23)
  • Task (27-31)
  • Task (33-41)
Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (3)
Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
  • Task (46-46)
Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (49-49)
  • Task (56-56)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (5)
  • Task (25-29)
  • Task (35-66)
  • Task (78-86)
  • Task (92-99)
  • PlayerService (8-113)
Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (2)
Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (4)
  • Task (25-29)
  • Task (35-66)
  • Task (78-86)
  • Task (92-99)
Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
  • Task (46-46)
🪛 GitHub Check: Codeac Code Quality
Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs

[warning] 102-110: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:28


[warning] 28-36: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:102


[warning] 123-131: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:28


[warning] 28-36: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:123


[warning] 146-155: CodeDuplication
This block of 9 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:102


[warning] 102-111: CodeDuplication
This block of 9 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:146


[warning] 172-181: CodeDuplication
This block of 9 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:123


[warning] 123-132: CodeDuplication
This block of 9 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:172


[warning] 197-210: CodeDuplication
This block of 13 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:118


[warning] 118-131: CodeDuplication
This block of 13 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:197


[warning] 226-236: CodeDuplication
This block of 10 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:121


[warning] 121-131: CodeDuplication
This block of 10 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:226

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (44)
Dotnet.Samples.AspNetCore.WebApi.Tests/packages.lock.json (3)

1003-1005: Updated Microsoft.OpenApi to version 1.6.23
The resolved version and corresponding content hash for Microsoft.OpenApi have been updated. Please verify that downstream dependencies or configuration settings relying on the previous version still work correctly with 1.6.23.


1326-1336: Upgrade Swashbuckle.AspNetCore to version 8.0.0 and update its transitive dependencies
The Swashbuckle.AspNetCore package and its related components (Swagger, SwaggerGen, and SwaggerUI) have been updated to version 8.0.0. This major upgrade might introduce breaking changes in the Swagger configuration or customization logic. Please review your API documentation setup and sample endpoints to ensure compatibility with the new version.


1645-1647: Update project dependency range for Swashbuckle.AspNetCore
The project dependency for Swashbuckle.AspNetCore has been revised to use the range [8.0.0, ), ensuring that only version 8.0.0 or higher is picked up. Confirm that this change aligns with the rest of the dependency graph and that no conflicts arise with other packages referencing earlier versions.

Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerStubs.cs (3)

7-7: Namespace organization improvement.

Moving the class to a dedicated .Utilities namespace provides better code organization and clearly indicates this class's purpose as a testing utility, which aligns with the Repository pattern implementation.


9-14: Well-documented stub definition.

The XML documentation clearly explains what a Stub is, how it differs from other test doubles, and provides a practical example. This helps developers understand when and how to use this class appropriately.


15-22: Focused single responsibility.

The class now has a single clear responsibility - providing stubs for model validation errors. This is consistent with the class name and the newly added documentation. The removal of database-related methods helps maintain the Single Responsibility Principle.

Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (2)

5-5: Proper namespace organization.

Moving PlayerFakes into the .Utilities namespace improves organization and keeps test utilities properly grouped.


7-13: Good documentation of testing concepts.

The added XML documentation clearly explains the concept of a "Fake" in testing, which helps developers understand the purpose and appropriate use of this class.

Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1)

6-12: Well-implemented Repository pattern.

The PlayerRepository class correctly:

  1. Inherits from the generic Repository<Player> base class
  2. Implements the IPlayerRepository interface
  3. Uses constructor injection for the database context
  4. Properly implements the player-specific query method

The implementation leverages the modern C# primary constructor syntax and uses async/await correctly.

Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (1)

3-9: Well-documented interface with appropriate generic constraints.

The interface is properly documented and uses the correct generic constraint (where T : class), which is required for entities that will be used with EF Core.

Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)

7-10: Well-designed specialized repository interface.

The IPlayerRepository properly extends the generic repository interface and includes appropriate documentation.

Dotnet.Samples.AspNetCore.WebApi/Program.cs (1)

39-41: Good implementation of dependency injection for the Repository pattern.

The code correctly registers the repository and service implementations with their respective interfaces, following the Dependency Injection principle. The addition of memory cache registration is also appropriate for supporting the caching functionality in the service layer.

Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerMocks.cs (2)

8-8: Appropriate namespace update for test utilities.

Moving the PlayerMocks class to a dedicated Utilities namespace improves code organization.


10-16: Good documentation practice for test utilities.

The XML comments clearly explain the purpose of mocks in testing, which is valuable for developers who might be less familiar with mocking concepts.

Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (3)

5-7: Good implementation of the generic Repository pattern.

The Repository class correctly implements the IRepository interface with the generic type constraint. The constraint to class types is appropriate since entity types in an EF Core context are expected to be reference types.


8-15: Good encapsulation of DbContext and DbSet.

The constructor properly initializes the DbContext and obtains the DbSet for the entity type. Protected access is appropriate to allow derived classes to access these members.


23-23: Concise implementation of GetAllAsync.

The method efficiently retrieves all entities using a single expression with ToListAsync.

Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (7)

6-6: Documentation properly updated to reflect Repository pattern.

The interface summary correctly reflects the change from direct database access to using a repository.


11-11: Method documentation aligned with Repository pattern.

The CreateAsync method summary now correctly refers to adding a Player to the repository.


18-18: Method documentation aligned with Repository pattern.

The RetrieveAsync method summary now correctly refers to retrieving players from the repository.


25-25: Method documentation aligned with Repository pattern.

The RetrieveByIdAsync method summary now correctly refers to retrieving a Player from the repository.


35-35: Method documentation aligned with Repository pattern.

The RetrieveBySquadNumberAsync method summary now correctly refers to retrieving a Player from the repository.


45-45: Method documentation aligned with Repository pattern.

The UpdateAsync method summary now correctly refers to updating a Player in the repository.


52-52: Method documentation aligned with Repository pattern.

The DeleteAsync method summary now correctly refers to removing a Player from the repository.

Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs (3)

17-27: Use of in-memory testing connection is appropriate
Returning a live in-memory connection from this method is a valid testing approach. Ensure that any test harness disposes the returned dbConnection to avoid potential resource leaks.


29-34: Straightforward DbContext creation
This method simply instantiates a PlayerDbContext with the supplied options. The design is clear and keeps the testing code clean.


49-53: Effective database seeding
Seeding the database with PlayerFakes.CreateStarting11() is a convenient way to initialize realistic test data.

Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (1)

4-4: Consistent category tagging
Switching all test methods to [Trait("Category", "Unit")] promotes consistency and clarity across the test suite.

Also applies to: 10-10, 19-19, 38-38, 59-59, 92-92, 115-115, 136-136, 158-158, 181-181, 206-206, 238-238, 258-258, 280-280, 308-308, 330-330

Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (9)

9-9: Repository injection
Receiving the IPlayerRepository through constructor injection and storing it in _playerRepository aligns well with the repository pattern for improved testability and maintainability.

Also applies to: 17-17


27-27: Delegated creation
Using _playerRepository.AddAsync(player) neatly separates concerns and removes direct DbContext dependencies here.


55-55: Retrieval from repository
Fetching data through GetAllAsync() consolidates read logic inside the repository, fostering cleaner service code.


68-69: ID-based retrieval
Shifting ID lookups to FindByIdAsync clarifies responsibility for data access in a single repository layer.


71-72: Squad-number retrieval
Relying on FindBySquadNumberAsync ensures the service remains database-agnostic, consistent with the repository abstraction.


80-80: Pattern matching for entity checks
Using if (entity is Player ...) is a succinct way to confirm the record exists before proceeding.


83-83: Centralized update
Delegating updates to UpdateAsync keeps the service thin and centralizes persistence concerns within the repository.


94-94: Existence check before delete
Verifying entity existence prevents unnecessary repository calls or exceptions. This is a prudent approach.


96-96: Remove operation
Invoking RemoveAsync(id) keeps deletion logic consistent with the broader repository pattern.

Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (7)

1-18: LGTM! The class setup looks good.

The implementation of IDisposable is appropriate for cleaning up environment variables after tests. The constructor properly sets up the test environment.


23-40: The test for CreateAsync properly verifies repository and cache interactions.

The test correctly validates that CreateAsync adds a player to the repository and clears the memory cache. The Arrange-Act-Assert pattern is well implemented.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 28-36: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:102


[warning] 28-36: CodeDuplication
This block of 8 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:123


46-68: Well-structured test for cache behavior in RetrieveAsync.

The test properly verifies that when the repository returns players, they're stored in cache and returned to the caller. Clear assertions validate all expected interactions.


70-93: Nice performance test for caching behavior.

This test effectively demonstrates the performance benefit of caching by measuring execution times. The verification that TryGetValue is called exactly twice ensures the cache is being checked appropriately.


195-215: The test for UpdateAsync is well-structured.

The test correctly verifies that when updating a player, the service retrieves it first, then updates the repository, and finally clears the cache.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 197-210: CodeDuplication
This block of 13 lines is too similar to Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:118


243-252: Good utility method for measuring execution time.

The ExecutionTimeAsync method is a well-implemented utility for measuring the execution time of asynchronous operations, which is essential for the performance comparison test.


254-267: Proper implementation of the dispose pattern.

The dispose pattern is correctly implemented with both the virtual Dispose(bool) method and the non-virtual Dispose() method that suppresses finalization.

Copy link

@nanotaboada nanotaboada merged commit 68b3791 into master Mar 30, 2025
21 checks passed
@nanotaboada nanotaboada deleted the feature/repository-pattern branch March 30, 2025 22:09
@coderabbitai coderabbitai bot mentioned this pull request Apr 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor PlayerServiceTests to reduce setup code duplication Consider implementing a generic Repository pattern
1 participant