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
-
Visual Studio:
- Open Test Explorer (Test → Test Explorer)
- Right-click project → Run Tests
- Or right-click individual test → Run Test
-
JetBrains Rider:
- Open Unit Tests window (View → Tool Windows → Unit Tests)
- Right-click project → Run Unit Tests
- Or use
Ctrl+U, Ctrl+Rshortcut
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 (
RealDatabaseFixtureonly) - Check connection string in
appsettings.Testing.json - Use In-Memory database for tests that don't need real database
"Token validation failed"
- Verify
Jwt:SecretKeymatches 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.Serverinstead 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
- Use In-Memory Database for most tests: Faster, no dependencies
- Use Real Database for critical paths: Migrations, constraints, transactions
- Isolate tests: Each test should be independent
- Use unique identifiers:
Guid.NewGuid()for slugs, emails - Clean up after tests: Use
IDisposablefixtures - Use FluentAssertions: More readable assertions
- Test happy paths AND error cases: Both success and failure scenarios
- 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:
- Follow existing test structure and naming conventions
- Use
TestAuthHelperfor common operations - Ensure tests are isolated and don't depend on execution order
- Add test documentation in this README
- 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.