Course contentsShow
← C#
Lesson 1658 of 1,90815. Software Quality and TestingFree lesson

Handling Repository Pattern Tests

Write integration tests for repository implementations to ensure query correctness.

In this lesson, you will learn how to write reliable integration tests for your Repository pattern implementations to verify that your LINQ queries and data access logic behave correctly against a real database.

Why Mocking Isn't Enough

When working with the Repository pattern, we often use mocks for unit testing, but mocking DbSet or IQueryable is notoriously fragile. Mocks don't know how to translate your complex LINQ queries into SQL. If you accidentally write a query that performs an N+1 issue or uses an unsupported operator, your unit tests will pass, but your application will crash at runtime. Integration testing the repository ensures the translation between your C# code and the database engine is actually valid.

Testing the Repository

To test a repository, you need a live database instance. Using an in-memory provider (like InMemoryDatabase for EF Core) is often discouraged because it lacks the relational integrity and specific SQL behaviors of your production database. Instead, aim to use a real database (or Testcontainers) to execute the queries.

Consider a simple GetActiveUsersAsync method:

public async Task<List<User>> GetActiveUsersAsync() 
    => await _context.Users.Where(u => u.IsActive).ToListAsync();

Your integration test should follow the Arrange-Act-Assert pattern:

  1. Arrange: Use your DbContext to seed specific data into the database (some active users, some inactive).
  2. Act: Call the repository method under test.
  3. Assert: Verify that the returned list contains only the active users, confirming the LINQ filter logic is correctly interpreted by the database.
[Fact]
public async Task GetActiveUsersAsync_ReturnsOnlyActiveUsers()
{
    // Arrange: Seed database directly via context
    _context.Users.AddRange(new User { IsActive = true }, new User { IsActive = false });
    await _context.SaveChangesAsync();

    // Act
    var result = await _repository.GetActiveUsersAsync();

    // Assert
    Assert.Single(result);
    Assert.True(result.All(u => u.IsActive));
}

By verifying the result against an actual database, you guarantee that your mapping, filtering, and asynchronous data retrieval work exactly as expected in the production environment.

Key Takeaway: Integration tests for repositories are essential because they validate that your LINQ-to-SQL logic executes correctly against the database engine, catching errors that mocks would otherwise ignore.