184 lines
4.5 KiB
Markdown
184 lines
4.5 KiB
Markdown
# Koogle Test Suite
|
|
|
|
Comprehensive testing infrastructure for the Koogle club management application.
|
|
|
|
## Test Projects
|
|
|
|
### Koogle.Tests
|
|
Main test project containing:
|
|
- **Unit Tests**: Domain entities, services, Fluxor reducers
|
|
- **Integration Tests**: API endpoints, database operations
|
|
- **Component Tests**: bUnit tests for Blazor components
|
|
- **Performance Tests**: Response time and memory allocation tests
|
|
|
|
### Koogle.E2E
|
|
End-to-end tests using Playwright:
|
|
- Authentication flow tests
|
|
- User journey tests
|
|
- UI interaction tests
|
|
|
|
## Running Tests
|
|
|
|
### All Tests
|
|
```bash
|
|
dotnet test test/Koogle.Tests
|
|
```
|
|
|
|
### Specific Test Categories
|
|
|
|
```bash
|
|
# Unit tests only
|
|
dotnet test test/Koogle.Tests --filter "FullyQualifiedName~Unit"
|
|
|
|
# Integration tests only
|
|
dotnet test test/Koogle.Tests --filter "FullyQualifiedName~Integration"
|
|
|
|
# Component tests only
|
|
dotnet test test/Koogle.Tests --filter "FullyQualifiedName~Components"
|
|
|
|
# Performance tests only
|
|
dotnet test test/Koogle.Tests --filter "FullyQualifiedName~Performance"
|
|
```
|
|
|
|
### E2E Tests
|
|
|
|
Before running E2E tests:
|
|
1. Install Playwright browsers:
|
|
```bash
|
|
pwsh test/Koogle.E2E/bin/Debug/net9.0/playwright.ps1 install
|
|
```
|
|
|
|
2. Start the application:
|
|
```bash
|
|
dotnet run --project src/Koogle.Web
|
|
```
|
|
|
|
3. Run E2E tests:
|
|
```bash
|
|
E2E_BASE_URL=https://localhost:7001 dotnet test test/Koogle.E2E
|
|
```
|
|
|
|
Environment variables:
|
|
- `E2E_BASE_URL`: Application URL (default: https://localhost:7001)
|
|
- `E2E_HEADLESS`: Set to "false" to see browser (default: headless)
|
|
- `E2E_SLOWMO`: Milliseconds to slow down operations for debugging
|
|
|
|
### Test Coverage
|
|
|
|
```bash
|
|
dotnet test test/Koogle.Tests --collect:"XPlat Code Coverage"
|
|
```
|
|
|
|
Report location: `test/Koogle.Tests/TestResults/*/coverage.cobertura.xml`
|
|
|
|
## Test Structure
|
|
|
|
```
|
|
test/
|
|
├── Koogle.Tests/
|
|
│ ├── Common/ # Shared test utilities
|
|
│ │ ├── TestDataGenerator.cs # Bogus-based test data
|
|
│ │ └── MockExtensions.cs # Mock setup helpers
|
|
│ │
|
|
│ ├── Unit/
|
|
│ │ ├── Domain/ # Entity tests
|
|
│ │ ├── Services/ # Service unit tests
|
|
│ │ └── Store/ # Fluxor reducer tests
|
|
│ │
|
|
│ ├── Integration/ # API & DB integration tests
|
|
│ │
|
|
│ ├── Components/ # bUnit Blazor tests
|
|
│ │
|
|
│ └── Performance/ # Performance benchmarks
|
|
│
|
|
└── Koogle.E2E/
|
|
├── PageObjectModels/ # Page abstractions
|
|
└── *Tests.cs # E2E test files
|
|
```
|
|
|
|
## Test Patterns
|
|
|
|
### AAA Pattern
|
|
All tests follow Arrange-Act-Assert:
|
|
```csharp
|
|
[Fact]
|
|
public async Task GetByIdAsync_ReturnsClub_WhenExists()
|
|
{
|
|
// Arrange
|
|
var club = TestDataGenerator.CreateClub();
|
|
_repositoryMock.SetupGetByIdAsync(club.Id, club);
|
|
|
|
// Act
|
|
var result = await _sut.GetByIdAsync(club.Id);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result!.Id.Should().Be(club.Id);
|
|
}
|
|
```
|
|
|
|
### Theory-Based Testing
|
|
For parameterized tests:
|
|
```csharp
|
|
[Theory]
|
|
[InlineData(ExpenseCalculation.None)]
|
|
[InlineData(ExpenseCalculation.Average)]
|
|
[InlineData(ExpenseCalculation.Maximum)]
|
|
public async Task CreateAsync_HandlesAllExpenseCalculationTypes(ExpenseCalculation calc)
|
|
{
|
|
// Test each enum value
|
|
}
|
|
```
|
|
|
|
### State Immutability Testing
|
|
For Fluxor reducers:
|
|
```csharp
|
|
[Fact]
|
|
public void Reducers_DoNotMutateOriginalState()
|
|
{
|
|
var originalState = ClubState.Initial with { Clubs = [...] };
|
|
var originalCount = originalState.Clubs.Count;
|
|
|
|
ClubReducers.OnDeleteClubSuccess(originalState, action);
|
|
|
|
originalState.Clubs.Should().HaveCount(originalCount);
|
|
}
|
|
```
|
|
|
|
## Writing New Tests
|
|
|
|
### 1. Use TestDataGenerator
|
|
```csharp
|
|
var club = TestDataGenerator.CreateClub(
|
|
name: "My Club",
|
|
expenseCalculation: ExpenseCalculation.Average);
|
|
```
|
|
|
|
### 2. Use MockExtensions
|
|
```csharp
|
|
_repositoryMock
|
|
.SetupGetAllAsync(clubs)
|
|
.SetupAddAsync();
|
|
```
|
|
|
|
### 3. Use FluentAssertions
|
|
```csharp
|
|
result.Should().NotBeNull();
|
|
result.Should().HaveCount(3);
|
|
result.Should().Contain(x => x.Name == "Club A");
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
| Package | Purpose |
|
|
|---------|---------|
|
|
| xUnit | Test framework |
|
|
| FluentAssertions | Readable assertions |
|
|
| Moq | Mocking |
|
|
| bUnit | Blazor component testing |
|
|
| Bogus | Test data generation |
|
|
| AutoFixture | Object creation |
|
|
| Microsoft.AspNetCore.Mvc.Testing | Integration testing |
|
|
| Microsoft.Playwright | E2E testing |
|
|
| Coverlet | Code coverage |
|
|
| RichardSzalay.MockHttp | MockHttp for HttpClient | |