This document describes the comprehensive testing strategy for the BankTracker GraphQL application.
The testing infrastructure includes:
- Unit Tests: xUnit for .NET backend services and repositories
- Integration Tests: xUnit with WebApplicationFactory for GraphQL API
- E2E Tests: Playwright for full-stack user flows
PhantomDave.BankTracking.UnitTests/
├── Services/
│ ├── JwtTokenServiceTests.cs (6 tests)
│ └── AccountServiceTests.cs (11 tests)
└── Repositories/ (ready for expansion)
PhantomDave.BankTracking.IntegrationTests/
├── GraphQL/
│ └── AccountIntegrationTests.cs (7 tests)
└── Helpers/
└── GraphQLTestFactory.cs
frontend/
├── e2e/
│ └── app.spec.ts (3 E2E tests)
└── playwright.config.ts
# Run all unit tests
dotnet test PhantomDave.BankTracking.UnitTests/PhantomDave.BankTracking.UnitTests.csproj
# Run with detailed output
dotnet test PhantomDave.BankTracking.UnitTests/PhantomDave.BankTracking.UnitTests.csproj --logger "console;verbosity=detailed"
# Run with code coverage
dotnet test PhantomDave.BankTracking.UnitTests/PhantomDave.BankTracking.UnitTests.csproj --collect:"XPlat Code Coverage"Current Status: ✅ 17/17 tests passing
# Run integration tests
dotnet test PhantomDave.BankTracking.IntegrationTests/PhantomDave.BankTracking.IntegrationTests.csproj
# Run with detailed output
dotnet test PhantomDave.BankTracking.IntegrationTests/PhantomDave.BankTracking.IntegrationTests.csproj --logger "console;verbosity=detailed"Current Status:
cd frontend
# Run E2E tests (headless)
npm run test:e2e
# Run E2E tests with browser UI
npm run test:e2e:headed
# Run E2E tests in interactive UI mode
npm run test:e2e:uiCurrent Status: ✅ Playwright configured and ready
# From repository root
dotnet test
cd frontend && npm run test:e2eThe unit tests cover:
- ✅ Token creation with valid inputs
- ✅ Token creation with roles
- ✅ Expiration time setting
- ✅ JTI claim inclusion
- ✅ Unique token generation
- ✅ Get account by ID (valid/invalid)
- ✅ Get account by email
- ✅ Create account with valid data
- ✅ Create account validation (empty email/password)
- ✅ Create account duplicate email check
- ✅ Update account
- ✅ Update account with invalid ID
- ✅ Login with valid credentials
- ✅ Login with invalid password
- ✅ Login with non-existent email
Integration tests verify:
- ✅ GraphQL endpoint accessibility
- ✅ Account creation via GraphQL mutation
- ✅ Duplicate email handling
- ✅ Invalid password error handling
⚠️ Token verification (needs schema fix)⚠️ Login flow (needs schema fix)⚠️ Authenticated queries (needs schema fix)
Playwright E2E tests verify:
- ✅ Homepage loading
- ✅ Login form presence
- ✅ Navigation functionality
- Isolation: Use mocks (Moq) to isolate units under test
- Naming: Use descriptive test names:
MethodName_Scenario_ExpectedResult - Arrange-Act-Assert: Structure tests clearly
- Coverage: Aim for >80% code coverage for business logic
- In-Memory Database: Tests use EF Core InMemory provider
- Test Environment: Tests run in "Testing" environment to skip migrations
- Factory Pattern:
GraphQLTestFactoryprovides consistent test setup - Cleanup: Each test uses fresh database state
- Real Browser: Playwright uses real Chromium browser
- Selectors: Use semantic selectors (accessibility IDs, roles)
- Waits: Use Playwright's auto-waiting features
- Screenshots: Captured on failure for debugging
- Traces: Enabled on retry for detailed debugging
Why xUnit?
- Modern, minimalistic syntax for .NET 10
- Built-in parallel test execution for faster CI
- Excellent dependency injection support
- Industry standard for new .NET projects
- Great integration with Visual Studio and CLI
Alternatives Considered:
- NUnit: More verbose, better for legacy projects
- MSTest: Microsoft ecosystem lock-in
Why Playwright?
- Cross-browser support (Chromium, Firefox, WebKit)
- Modern API with auto-waiting
- Excellent debugging tools (traces, screenshots)
- Better GraphQL testing support
- Multi-tab and multi-origin support
- Native TypeScript support
Alternatives Considered:
- Cypress: Easier but limited to Chrome, same-origin restrictions
- Selenium: Older, less reliable, more flaky tests
name: 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: '10.0.x'
- name: Run Unit Tests
run: dotnet test PhantomDave.BankTracking.UnitTests/
- name: Run Integration Tests
run: dotnet test PhantomDave.BankTracking.IntegrationTests/
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install Dependencies
working-directory: frontend
run: npm ci
- name: Install Playwright
working-directory: frontend
run: npx playwright install --with-deps chromium
- name: Run E2E Tests
working-directory: frontend
run: npm run test:e2eGenerate code coverage report:
# Run tests with coverage
dotnet test --collect:"XPlat Code Coverage" --results-directory ./TestResults
# Install reportgenerator tool (one-time)
dotnet tool install -g dotnet-reportgenerator-globaltool
# Generate HTML report
reportgenerator \
-reports:"./TestResults/**/coverage.cobertura.xml" \
-targetdir:"./CoverageReport" \
-reporttypes:Html
# View report
open ./CoverageReport/index.html- Create test file in appropriate directory:
PhantomDave.BankTracking.UnitTests/Services/MyServiceTests.cs - Follow AAA pattern (Arrange-Act-Assert)
- Use descriptive test names
- Mock dependencies with Moq
Example:
public class MyServiceTests
{
[Fact]
public async Task MethodName_WhenCondition_ThenExpectedBehavior()
{
// Arrange
var mockDependency = new Mock<IDependency>();
var service = new MyService(mockDependency.Object);
// Act
var result = await service.MethodName();
// Assert
Assert.NotNull(result);
mockDependency.Verify(d => d.SomeMethod(), Times.Once);
}
}- Use
IClassFixture<GraphQLTestFactory>for test class - Create GraphQL queries/mutations as strings
- Use
HttpClientto post to/graphql - Assert on response content
- Create test file in
frontend/e2e/ - Use Playwright's
testandexpectfunctions - Navigate with
page.goto() - Interact with elements using semantic selectors
- Use auto-waiting features
# Restore packages
dotnet restore
# Clean and rebuild
dotnet clean
dotnet buildThe tests use in-memory database. If you see database errors:
- Ensure
UseEnvironment("Testing")is set inGraphQLTestFactory - Check that
Program.csskips migration in Testing environment
# Reinstall Playwright browsers
cd frontend
npx playwright install --with-deps chromium
# Check if Angular dev server starts
npm startIncrease timeout in playwright.config.ts:
use: {
baseURL: 'http://localhost:4200',
timeout: 60000, // Increase from default 30s
}- Fix remaining 4 integration tests
- Add repository layer unit tests
- Add finance record service unit tests
- Expand E2E tests to cover full user journeys
- Add mutation testing with Stryker.NET
- Integrate coverage reporting into CI
- Add performance tests for critical queries
- Add contract tests for GraphQL schema
- Add visual regression tests with Playwright
- Add load tests with k6 or Artillery
- Add accessibility tests with axe-core