Testing Philosophy
Integration Over Unit
Focus on testing complete workflows rather than individual units in isolation
Test Real Dependencies
Use real PostgreSQL, RabbitMQ, and Redis in tests via Docker
Fast Feedback
Keep test suites fast with parallel execution and test data cleanup
Reliable & Deterministic
Tests should produce consistent results and not depend on external state
Test Types
Integration Tests
Test complete features through the HTTP API with real dependencies. Characteristics:- Use
WebApplicationFactory<Program>to host the API - Real database (PostgreSQL in Docker)
- Real message bus (RabbitMQ)
- Actual authentication/authorization
- Test entire request/response cycle
BookSeatIntegrationTests.cs
Unit Tests
Test individual components in isolation with mocked dependencies. Use for:- Complex business logic
- Validation rules
- Utility methods
- Domain models
BookingPaymentValidatorTests.cs
End-to-End Tests
Test complete user journeys across multiple services. Example Scenarios:- User creates trip → Passenger books seat → Driver accepts → Trip completes → Payment settles
- Passenger searches trips → Books seat → Cancels booking → Refund processed
BookingFlowE2ETests.cs
Test Infrastructure
WebApplicationFactory Setup
TestWebApplicationFactory.cs
Database Fixture
Use Docker to run PostgreSQL for tests.TestDatabaseFixture.cs
Test Data Builders
Use builder pattern for creating test data.TripTestDataBuilder.cs
Testing Patterns
Arrange-Act-Assert
Structure all tests with clear sections.Test Data Cleanup
Clean up test data after each test.Async Testing
Always use async/await in tests.Theory Tests
Use[Theory] for parameterized tests.
Running Tests
Command Line
Visual Studio / Rider
Use the built-in test runner for interactive testing and debugging.Best Practices
Test Behavior, Not Implementation
Test Behavior, Not Implementation
Focus on testing observable behavior and outcomes, not internal implementation details.
Keep Tests Independent
Keep Tests Independent
Each test should be able to run in isolation without depending on other tests.
Use Descriptive Test Names
Use Descriptive Test Names
Test names should clearly describe what is being tested and the expected outcome.
One Assert Per Concept
One Assert Per Concept
While multiple asserts are okay, they should all relate to verifying the same logical concept.
Mock External Services
Mock External Services
Use test doubles for external HTTP APIs, payment gateways, etc. Test real dependencies like databases.
Coverage Goals
Target Coverage:
- Critical paths: 100%
- Business logic: 80%+
- Overall: 70%+
Continuous Integration
Tests run automatically on every pull request..github/workflows/test.yml
Next Steps
Adding Features
Write tests for your new features
Architecture
Understand the system architecture