Files
ColaFlow/colaflow-api/tests/Modules/Identity/ColaFlow.Modules.Identity.IntegrationTests/README.md
Yaojia Wang 4183b10b39
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Commit all scripts
2025-11-03 17:19:20 +01:00

11 KiB

ColaFlow Identity Module - Integration Tests

Professional .NET Integration Test project for Day 5 Refresh Token and RBAC functionality.

Project Overview

This test project provides comprehensive integration testing for:

  • Phase 1: Refresh Token functionality (token refresh, rotation, revocation)
  • Phase 2: Role-Based Access Control (RBAC) (role assignment, JWT claims, role persistence)
  • Day 4 Regression: Authentication basics (registration, login, password hashing)

Project Structure

ColaFlow.Modules.Identity.IntegrationTests/
├── Infrastructure/
│   ├── ColaFlowWebApplicationFactory.cs   # Custom WebApplicationFactory
│   ├── DatabaseFixture.cs                 # In-Memory database fixture
│   ├── RealDatabaseFixture.cs            # PostgreSQL database fixture
│   └── TestAuthHelper.cs                  # Authentication test utilities
├── Identity/
│   ├── AuthenticationTests.cs             # Day 4 regression tests
│   ├── RefreshTokenTests.cs               # Day 5 Phase 1 tests
│   └── RbacTests.cs                       # Day 5 Phase 2 tests
├── appsettings.Testing.json               # Test configuration
└── ColaFlow.Modules.Identity.IntegrationTests.csproj

Test Categories

1. Authentication Tests (Day 4 Regression)

  • RegisterTenant with valid/invalid data
  • Login with correct/incorrect credentials
  • Protected endpoint access with/without token
  • JWT token claims validation
  • Password hashing verification
  • Complete auth flow (register → login → access)

Total Tests: 10

2. Refresh Token Tests (Day 5 Phase 1)

  • RegisterTenant returns access + refresh tokens
  • Login returns access + refresh tokens
  • RefreshToken returns new token pair
  • Old refresh token cannot be reused (token rotation)
  • Invalid refresh token fails
  • Logout revokes refresh token
  • Refresh token maintains user identity
  • Multiple refresh operations work
  • Expired refresh token fails

Total Tests: 9

3. RBAC Tests (Day 5 Phase 2)

  • RegisterTenant assigns TenantOwner role
  • JWT contains role claims
  • Login preserves role
  • RefreshToken preserves role
  • /api/auth/me returns user role
  • JWT contains all required role claims
  • Multiple token refresh maintains role
  • Protected endpoint access with valid role succeeds
  • Protected endpoint access without token fails
  • Protected endpoint access with invalid token fails
  • Role consistency across all authentication flows

Total Tests: 11

Grand Total: 30 Integration Tests

Test Infrastructure

WebApplicationFactory

The ColaFlowWebApplicationFactory supports two database modes:

1. In-Memory Database (Default)

  • Fast, isolated tests
  • No external dependencies
  • Each test class gets its own database instance
  • Recommended for CI/CD pipelines
var factory = new ColaFlowWebApplicationFactory(useInMemoryDatabase: true);

2. Real PostgreSQL Database

  • Tests actual database behavior
  • Verifies migrations and real database constraints
  • Requires PostgreSQL running on localhost
  • Recommended for local testing
var factory = new ColaFlowWebApplicationFactory(useInMemoryDatabase: false);

Database Fixtures

DatabaseFixture (In-Memory)

  • Implements IClassFixture<DatabaseFixture>
  • Provides isolated database per test class
  • Automatic cleanup after tests

RealDatabaseFixture (PostgreSQL)

  • Implements IClassFixture<RealDatabaseFixture>
  • Creates unique test database per test run
  • Automatic cleanup (database deletion) after tests

NuGet Packages

Package Version Purpose
xunit 2.9.2 Test framework
xunit.runner.visualstudio 2.8.2 Visual Studio test runner
Microsoft.AspNetCore.Mvc.Testing 9.0.0 WebApplicationFactory
Microsoft.EntityFrameworkCore.InMemory 9.0.0 In-Memory database
Npgsql.EntityFrameworkCore.PostgreSQL 9.0.4 PostgreSQL provider
FluentAssertions 7.0.0 Fluent assertion library
System.IdentityModel.Tokens.Jwt 8.14.0 JWT token parsing

Running Tests

Prerequisites

For In-Memory Tests (No external dependencies):

  • .NET 9.0 SDK installed

For PostgreSQL Tests:

  • PostgreSQL running on localhost:5432
  • Username: postgres
  • Password: postgres
  • Database: colaflow_test (auto-created)

Command Line

Run All Tests

cd c:\Users\yaoji\git\ColaCoder\product-master\colaflow-api
dotnet test tests/Modules/Identity/ColaFlow.Modules.Identity.IntegrationTests

Run Specific Test Class

# Refresh Token Tests only
dotnet test --filter "FullyQualifiedName~RefreshTokenTests"

# RBAC Tests only
dotnet test --filter "FullyQualifiedName~RbacTests"

# Authentication Tests only
dotnet test --filter "FullyQualifiedName~AuthenticationTests"

Run Specific Test Method

dotnet test --filter "FullyQualifiedName~RefreshToken_ShouldReturnNewTokenPair"

Verbose Output

dotnet test --logger "console;verbosity=detailed"

Generate Coverage Report

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./coverage.lcov

Visual Studio / Rider

  1. Visual Studio:

    • Open Test Explorer (Test → Test Explorer)
    • Right-click project → Run Tests
    • Or right-click individual test → Run Test
  2. JetBrains Rider:

    • Open Unit Tests window (View → Tool Windows → Unit Tests)
    • Right-click project → Run Unit Tests
    • Or use Ctrl+U, Ctrl+R shortcut

Parallel Execution

By default, xUnit runs test classes in parallel but tests within a class sequentially. This is perfect for integration tests because:

  • Each test class uses its own DatabaseFixture (isolated database)
  • Tests within a class share the same database (sequential execution prevents conflicts)

To disable parallelization (for debugging):

[assembly: CollectionBehavior(DisableTestParallelization = true)]

Test Configuration

appsettings.Testing.json

{
  "ConnectionStrings": {
    "IdentityConnection": "Host=localhost;Port=5432;Database=colaflow_test;Username=postgres;Password=postgres"
  },
  "Jwt": {
    "SecretKey": "test-secret-key-min-32-characters-long-12345678901234567890",
    "Issuer": "ColaFlow.API.Test",
    "Audience": "ColaFlow.Web.Test",
    "ExpirationMinutes": "15",
    "RefreshTokenExpirationDays": "7"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

Override Configuration

You can override configuration in tests:

builder.ConfigureAppConfiguration((context, config) =>
{
    config.AddInMemoryCollection(new Dictionary<string, string>
    {
        ["Jwt:ExpirationMinutes"] = "5",
        ["Jwt:RefreshTokenExpirationDays"] = "1"
    });
});

Test Helpers

TestAuthHelper

Provides convenient methods for common test scenarios:

// Register and get tokens
var (accessToken, refreshToken) = await TestAuthHelper.RegisterAndGetTokensAsync(client);

// Login and get tokens
var (accessToken, refreshToken) = await TestAuthHelper.LoginAndGetTokensAsync(
    client, "tenant-slug", "email@test.com", "password");

// Parse JWT token
var claims = TestAuthHelper.ParseJwtToken(accessToken);

// Get specific claim
var userId = TestAuthHelper.GetClaimValue(accessToken, "user_id");

// Check role
bool isOwner = TestAuthHelper.HasRole(accessToken, "TenantOwner");

CI/CD Integration

GitHub Actions

name: Integration Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: 9.0.x
      - name: Restore dependencies
        run: dotnet restore
      - name: Build
        run: dotnet build --no-restore
      - name: Run Integration Tests
        run: dotnet test tests/Modules/Identity/ColaFlow.Modules.Identity.IntegrationTests --no-build --verbosity normal

Azure DevOps

trigger:
  - main

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: UseDotNet@2
    inputs:
      version: '9.0.x'
  - task: DotNetCoreCLI@2
    displayName: 'Restore'
    inputs:
      command: 'restore'
  - task: DotNetCoreCLI@2
    displayName: 'Build'
    inputs:
      command: 'build'
  - task: DotNetCoreCLI@2
    displayName: 'Test'
    inputs:
      command: 'test'
      projects: '**/ColaFlow.Modules.Identity.IntegrationTests.csproj'

Test Coverage Goals

  • Line Coverage: ≥ 80%
  • Branch Coverage: ≥ 70%
  • Critical Paths: 100% coverage for:
    • Token generation and refresh
    • Role assignment and persistence
    • Authentication flows

Troubleshooting

Test Failures

"Database connection failed"

  • Ensure PostgreSQL is running (RealDatabaseFixture only)
  • Check connection string in appsettings.Testing.json
  • Use In-Memory database for tests that don't need real database

"Token validation failed"

  • Verify Jwt:SecretKey matches between test config and API config
  • Check token expiration time is sufficient
  • Ensure clock skew tolerance is configured

"Test isolation issues"

  • Ensure each test class uses IClassFixture<DatabaseFixture>
  • Verify tests don't share global state
  • Use unique tenant slugs and emails (Guid.NewGuid())

"Port already in use"

  • The test server uses a random port by default
  • No need to stop the real API server
  • If issues persist, use _factory.Server instead of _factory.CreateClient()

Debug Tips

Enable Detailed Logging

builder.ConfigureLogging(logging =>
{
    logging.ClearProviders();
    logging.AddConsole();
    logging.SetMinimumLevel(LogLevel.Debug);
});

Inspect Database State

using var scope = Factory.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<IdentityDbContext>();
var users = db.Users.ToList();
// Inspect users...

Pause Test Execution

await Task.Delay(TimeSpan.FromSeconds(30)); // Inspect state manually

Best Practices

  1. Use In-Memory Database for most tests: Faster, no dependencies
  2. Use Real Database for critical paths: Migrations, constraints, transactions
  3. Isolate tests: Each test should be independent
  4. Use unique identifiers: Guid.NewGuid() for slugs, emails
  5. Clean up after tests: Use IDisposable fixtures
  6. Use FluentAssertions: More readable assertions
  7. Test happy paths AND error cases: Both success and failure scenarios
  8. Use descriptive test names: MethodName_Scenario_ExpectedResult

Future Enhancements

  • Add Testcontainers for PostgreSQL (no manual setup required)
  • Add performance benchmarks
  • Add load testing (k6 integration)
  • Add Swagger/OpenAPI contract tests
  • Add mutation testing (Stryker.NET)
  • Add E2E tests with Playwright

Contributing

When adding new tests:

  1. Follow existing test structure and naming conventions
  2. Use TestAuthHelper for common operations
  3. Ensure tests are isolated and don't depend on execution order
  4. Add test documentation in this README
  5. Verify tests pass with both In-Memory and Real database

License

This test project is part of ColaFlow and follows the same license.


Questions? Contact the QA team or refer to the main ColaFlow documentation.