mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
276 lines
6.7 KiB
Markdown
276 lines
6.7 KiB
Markdown
# Testing
|
|
|
|
This document describes the testing strategy and how to run tests for The Biergarten App.
|
|
|
|
## Overview
|
|
|
|
The project uses a multi-layered testing approach:
|
|
|
|
- **API.Specs** - BDD integration tests using Reqnroll (Gherkin)
|
|
- **Infrastructure.Repository.Tests** - Unit tests for data access layer
|
|
- **Service.Auth.Tests** - Unit tests for authentication business logic
|
|
|
|
## Running Tests with Docker (Recommended)
|
|
|
|
The easiest way to run all tests is using Docker Compose, which sets up an isolated test environment:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.test.yaml up --abort-on-container-exit
|
|
```
|
|
|
|
This command:
|
|
1. Starts a fresh SQL Server instance
|
|
2. Runs database migrations
|
|
3. Seeds test data
|
|
4. Executes all test suites in parallel
|
|
5. Exports results to `./test-results/`
|
|
6. Exits when tests complete
|
|
|
|
### View Test Results
|
|
|
|
```bash
|
|
# List test result files
|
|
ls -la test-results/
|
|
|
|
# View specific test results
|
|
cat test-results/api-specs/results.trx
|
|
cat test-results/repository-tests/results.trx
|
|
cat test-results/service-auth-tests/results.trx
|
|
```
|
|
|
|
### Clean Up
|
|
|
|
```bash
|
|
# Remove test containers and volumes
|
|
docker compose -f docker-compose.test.yaml down -v
|
|
```
|
|
|
|
## Running Tests Locally
|
|
|
|
You can run individual test projects locally without Docker:
|
|
|
|
### Integration Tests (API.Specs)
|
|
|
|
```bash
|
|
cd src/Core
|
|
dotnet test API/API.Specs/API.Specs.csproj
|
|
```
|
|
|
|
**Requirements**:
|
|
- SQL Server instance running
|
|
- Database migrated and seeded
|
|
- Environment variables set (DB connection, JWT secret)
|
|
|
|
### Repository Tests
|
|
|
|
```bash
|
|
cd src/Core
|
|
dotnet test Infrastructure/Infrastructure.Repository.Tests/Infrastructure.Repository.Tests.csproj
|
|
```
|
|
|
|
**Requirements**:
|
|
- SQL Server instance running (uses mock data)
|
|
|
|
### Service Tests
|
|
|
|
```bash
|
|
cd src/Core
|
|
dotnet test Service/Service.Auth.Tests/Service.Auth.Tests.csproj
|
|
```
|
|
|
|
**Requirements**:
|
|
- No database required (uses Moq for mocking)
|
|
|
|
## Test Coverage
|
|
|
|
### Current Coverage
|
|
|
|
**Authentication & User Management**:
|
|
- ✅ User registration with validation
|
|
- ✅ User login with JWT token generation
|
|
- ✅ Password hashing and verification (Argon2id)
|
|
- ✅ JWT token generation and claims
|
|
- ✅ Invalid credentials handling
|
|
- ✅ 404 error responses
|
|
|
|
**Repository Layer**:
|
|
- ✅ User account creation
|
|
- ✅ User credential management
|
|
- ✅ GetUserByUsername queries
|
|
- ✅ Stored procedure execution
|
|
|
|
**Service Layer**:
|
|
- ✅ Login service with password verification
|
|
- ✅ Register service with validation
|
|
- ✅ Business logic for authentication flow
|
|
|
|
### Planned Coverage
|
|
|
|
- [ ] Email verification workflow
|
|
- [ ] Password reset functionality
|
|
- [ ] Token refresh mechanism
|
|
- [ ] Brewery data management
|
|
- [ ] Beer post operations
|
|
- [ ] User follow/unfollow
|
|
- [ ] Image upload service
|
|
|
|
## Testing Frameworks & Tools
|
|
|
|
### xUnit
|
|
- Primary unit testing framework
|
|
- Used for Repository and Service layer tests
|
|
- Supports parallel test execution
|
|
|
|
### Reqnroll (Gherkin/BDD)
|
|
- Behavior-driven development framework
|
|
- Used for API integration tests
|
|
- Human-readable test scenarios in `.feature` files
|
|
|
|
### FluentAssertions
|
|
- Expressive assertion library
|
|
- Makes test assertions more readable
|
|
- Used across all test projects
|
|
|
|
### Moq
|
|
- Mocking framework for .NET
|
|
- Used in Service layer tests
|
|
- Enables isolated unit testing
|
|
|
|
### DbMocker
|
|
- Database mocking for repository tests
|
|
- Simulates SQL Server responses
|
|
- No real database required for unit tests
|
|
|
|
## Test Structure
|
|
|
|
### API.Specs (Integration Tests)
|
|
|
|
```
|
|
API.Specs/
|
|
├── Features/
|
|
│ ├── Authentication.feature # Login/register scenarios
|
|
│ └── UserManagement.feature # User CRUD scenarios
|
|
├── Steps/
|
|
│ ├── AuthenticationSteps.cs # Step definitions
|
|
│ └── UserManagementSteps.cs
|
|
└── Mocks/
|
|
└── TestApiFactory.cs # Test server setup
|
|
```
|
|
|
|
**Example Feature**:
|
|
```gherkin
|
|
Feature: User Authentication
|
|
As a user
|
|
I want to register and login
|
|
So that I can access the platform
|
|
|
|
Scenario: Successful user registration
|
|
Given I have valid registration details
|
|
When I register a new account
|
|
Then I should receive a JWT token
|
|
And my account should be created
|
|
```
|
|
|
|
### Infrastructure.Repository.Tests
|
|
|
|
```
|
|
Infrastructure.Repository.Tests/
|
|
├── AuthRepositoryTests.cs # Auth repository tests
|
|
├── UserAccountRepositoryTests.cs # User account tests
|
|
└── TestFixtures/
|
|
└── DatabaseFixture.cs # Shared test setup
|
|
```
|
|
|
|
### Service.Auth.Tests
|
|
|
|
```
|
|
Service.Auth.Tests/
|
|
├── LoginService.test.cs # Login business logic tests
|
|
└── RegisterService.test.cs # Registration business logic tests
|
|
```
|
|
|
|
## Writing Tests
|
|
|
|
### Unit Test Example (xUnit)
|
|
|
|
```csharp
|
|
public class LoginServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task LoginAsync_ValidCredentials_ReturnsToken()
|
|
{
|
|
// Arrange
|
|
var mockRepo = new Mock<IAuthRepository>();
|
|
var mockJwt = new Mock<IJwtService>();
|
|
var service = new AuthService(mockRepo.Object, mockJwt.Object);
|
|
|
|
// Act
|
|
var result = await service.LoginAsync("testuser", "password123");
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Token.Should().NotBeNullOrEmpty();
|
|
}
|
|
}
|
|
```
|
|
|
|
### Integration Test Example (Reqnroll)
|
|
|
|
```gherkin
|
|
Scenario: User login with valid credentials
|
|
Given a registered user with username "testuser"
|
|
When I POST to "/api/auth/login" with valid credentials
|
|
Then the response status should be 200
|
|
And the response should contain a JWT token
|
|
```
|
|
|
|
## Continuous Integration
|
|
|
|
Tests run automatically in CI/CD pipelines using the test Docker Compose configuration:
|
|
|
|
```bash
|
|
# CI/CD command
|
|
docker compose -f docker-compose.test.yaml build
|
|
docker compose -f docker-compose.test.yaml up --abort-on-container-exit
|
|
docker compose -f docker-compose.test.yaml down -v
|
|
```
|
|
|
|
Exit codes:
|
|
- `0` - All tests passed
|
|
- Non-zero - Test failures occurred
|
|
|
|
## Troubleshooting
|
|
|
|
### Tests Failing Due to Database Connection
|
|
|
|
Ensure SQL Server is running and environment variables are set:
|
|
```bash
|
|
docker compose -f docker-compose.test.yaml ps
|
|
```
|
|
|
|
### Port Conflicts
|
|
|
|
If port 1433 is in use, stop other SQL Server instances or modify the port in `docker-compose.test.yaml`.
|
|
|
|
### Stale Test Data
|
|
|
|
Clean up test database:
|
|
```bash
|
|
docker compose -f docker-compose.test.yaml down -v
|
|
```
|
|
|
|
### View Container Logs
|
|
|
|
```bash
|
|
docker compose -f docker-compose.test.yaml logs <service-name>
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Isolation**: Each test should be independent and not rely on other tests
|
|
2. **Cleanup**: Use fixtures and dispose patterns for resource cleanup
|
|
3. **Mocking**: Mock external dependencies in unit tests
|
|
4. **Descriptive Names**: Use clear, descriptive test method names
|
|
5. **Arrange-Act-Assert**: Follow AAA pattern in unit tests
|
|
6. **Given-When-Then**: Follow GWT pattern in BDD scenarios
|