Skip to main content
ClaudeWave
Skill68 repo starsupdated 14d ago

dotnet-integration-testing

This Claude Code skill configures a complete integration testing framework for .NET APIs using WebApplicationFactory for in-memory test servers, Testcontainers for real PostgreSQL databases, and helper utilities for authentication and database cleanup. Use it when setting up integration tests that verify full request pipelines with actual dependencies rather than mocks.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/ronnythedev/dotnet-clean-architecture-skills /tmp/dotnet-integration-testing && cp -r /tmp/dotnet-integration-testing/skills/22-dotnet-integration-testing ~/.claude/skills/dotnet-integration-testing
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Integration Test Setup

## Overview

Integration tests verify the full request pipeline:

- **WebApplicationFactory** - In-memory test server
- **Testcontainers** - Real PostgreSQL in Docker
- **Respawn** - Fast database cleanup between tests
- **Authentication helpers** - Test with different users/roles

## Quick Reference

| Component | Purpose |
|-----------|---------|
| `IntegrationTestWebAppFactory` | Custom test server factory |
| `BaseIntegrationTest` | Base class for all tests |
| `Respawner` | Database cleanup utility |
| `TestAuthHandler` | Fake authentication handler |

---

## Test Project Structure

```
tests/
└── {name}.Api.IntegrationTests/
    ├── Infrastructure/
    │   ├── IntegrationTestWebAppFactory.cs
    │   ├── BaseIntegrationTest.cs
    │   ├── TestAuthHandler.cs
    │   └── FakeUserContext.cs
    ├── {Feature}/
    │   ├── Create{Entity}Tests.cs
    │   └── Get{Entity}Tests.cs
    └── {name}.Api.IntegrationTests.csproj
```

---

## Template: Test Project File

```xml
<!-- tests/{name}.Api.IntegrationTests/{name}.Api.IntegrationTests.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="FluentAssertions" Version="6.12.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
    <PackageReference Include="Respawn" Version="6.1.0" />
    <PackageReference Include="Testcontainers.PostgreSql" Version="3.6.0" />
    <PackageReference Include="xunit" Version="2.6.2" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
    </PackageReference>
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\{name}.api\{name}.api.csproj" />
    <ProjectReference Include="..\..\src\{name}.infrastructure\{name}.infrastructure.csproj" />
  </ItemGroup>

</Project>
```

---

## Template: WebApplicationFactory

```csharp
// tests/{name}.Api.IntegrationTests/Infrastructure/IntegrationTestWebAppFactory.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Testcontainers.PostgreSql;
using {name}.infrastructure;

namespace {name}.Api.IntegrationTests.Infrastructure;

public class IntegrationTestWebAppFactory 
    : WebApplicationFactory<Program>, IAsyncLifetime
{
    private readonly PostgreSqlContainer _dbContainer = new PostgreSqlBuilder()
        .WithImage("postgres:15-alpine")
        .WithDatabase("testdb")
        .WithUsername("postgres")
        .WithPassword("postgres")
        .Build();

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureTestServices(services =>
        {
            // ═══════════════════════════════════════════════════════════════
            // REPLACE DATABASE WITH TEST CONTAINER
            // ═══════════════════════════════════════════════════════════════
            
            services.RemoveAll(typeof(DbContextOptions<ApplicationDbContext>));

            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseNpgsql(_dbContainer.GetConnectionString());
            });

            // ═══════════════════════════════════════════════════════════════
            // REPLACE AUTHENTICATION WITH TEST HANDLER
            // ═══════════════════════════════════════════════════════════════
            
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = TestAuthHandler.SchemeName;
                options.DefaultChallengeScheme = TestAuthHandler.SchemeName;
            })
            .AddScheme<TestAuthSchemeOptions, TestAuthHandler>(
                TestAuthHandler.SchemeName,
                options => { });

            // ═══════════════════════════════════════════════════════════════
            // REPLACE EXTERNAL SERVICES WITH FAKES
            // ═══════════════════════════════════════════════════════════════
            
            // services.RemoveAll<IEmailService>();
            // services.AddSingleton<IEmailService, FakeEmailService>();
        });

        builder.UseEnvironment("Testing");
    }

    public async Task InitializeAsync()
    {
        await _dbContainer.StartAsync();
        
        // Apply migrations
        using var scope = Services.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        await dbContext.Database.MigrateAsync();
    }

    public new async Task DisposeAsync()
    {
        await _dbContainer.StopAsync();
    }
}
```

---

## Template: Test Authentication Handler

```csharp
// tests/{name}.Api.IntegrationTests/Infrastructure/TestAuthHandler.cs
using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace {name}.Api.IntegrationTests.Infrastructure;

public class TestAuthSchemeOptions : AuthenticationSchemeOptions
{
    public Guid? UserId { get; set; }
    public string? Email { get; set; }
    public string[]? Roles { get; set; }
    public string[]? Permissions { get; set; }
}

public class TestAuthHandler : AuthenticationHandler<TestAuthSchemeOptions>
{
    public const string SchemeName = "TestScheme";
    public const string TestUserIdHeader = "X-Test-User-Id";
    public const string TestUserEmailHeader = "X-Test-User-Email";
dotnet-clean-architectureSkill

Scaffolds a complete .NET solution following Clean Architecture principles with proper layer separation (API, Application, Domain, Infrastructure). Creates project structure, dependency injection setup, and cross-cutting concerns configuration.

dotnet-cqrs-command-generatorSkill

Generates CQRS Commands with Handlers, Validators, and Request DTOs following Clean Architecture patterns. Commands represent actions that modify state and return Result types for proper error handling.

dotnet-cqrs-query-generatorSkill

Generates CQRS Queries with Handlers and Response DTOs for read operations. Uses Dapper for optimized read queries, bypassing the domain model for better performance.

dotnet-domain-entity-generatorSkill

Generates Domain Entities following DDD principles with factory methods, private setters, domain events, and proper encapsulation. Supports aggregate roots, child entities, and value objects.

dotnet-repository-patternSkill

Generates Repository interfaces and implementations following the Repository pattern. Provides data access abstraction for aggregate roots with EF Core implementations.

dotnet-ef-core-configurationSkill

Generates Entity Framework Core configurations using Fluent API. Maps domain entities to database tables with proper relationships, constraints, and conventions.

dotnet-legacy-api-controllersSkill

Generates RESTful API Controllers with proper routing, versioning, authorization, and MediatR integration. Follows REST conventions and Clean Architecture patterns.

dotnet-minimal-api-endpointsSkill

Generates Minimal API endpoints following Microsoft's recommended approach. Creates fast, testable HTTP APIs with minimal code using MapGet/MapPost/MapPut/MapDelete. Preferred over controller-based APIs for new projects.