platform/docs/testing_guide.md
2024-11-12 01:00:05 -07:00

343 lines
7.5 KiB
Markdown

# Testing Guide
## Overview
This guide outlines our testing approach, which follows Laravel's testing patterns while leveraging Dart's testing capabilities. It covers unit testing, integration testing, performance testing, and Laravel-style testing approaches.
## Test Types
### 1. Unit Tests
```dart
void main() {
group('Service Tests', () {
late Container container;
late UserService service;
setUp(() {
container = Container(reflector);
container.bind<Database>((c) => MockDatabase());
service = container.make<UserService>();
});
test('creates user', () async {
var user = await service.create({
'name': 'John Doe',
'email': 'john@example.com'
});
expect(user.name, equals('John Doe'));
expect(user.email, equals('john@example.com'));
});
test('validates user data', () {
expect(
() => service.create({'name': 'John Doe'}),
throwsA(isA<ValidationException>())
);
});
});
}
```
### 2. Integration Tests
```dart
void main() {
group('API Integration', () {
late Application app;
setUp(() async {
app = await createApplication();
await app.initialize();
});
tearDown(() async {
await app.shutdown();
});
test('creates user through API', () async {
var response = await app.post('/users', body: {
'name': 'John Doe',
'email': 'john@example.com'
});
expect(response.statusCode, equals(201));
expect(response.json['name'], equals('John Doe'));
});
test('handles validation errors', () async {
var response = await app.post('/users', body: {
'name': 'John Doe'
});
expect(response.statusCode, equals(422));
expect(response.json['errors'], contains('email'));
});
});
}
```
### 3. Performance Tests
```dart
void main() {
group('Performance Tests', () {
late Application app;
setUp(() async {
app = await createApplication();
await app.initialize();
});
test('handles concurrent requests', () async {
var stopwatch = Stopwatch()..start();
// Create 100 concurrent requests
var futures = List.generate(100, (i) =>
app.get('/users')
);
var responses = await Future.wait(futures);
stopwatch.stop();
// Verify responses
expect(responses, everyElement(
predicate((r) => r.statusCode == 200)
));
// Check performance
expect(
stopwatch.elapsedMilliseconds / responses.length,
lessThan(100) // Less than 100ms per request
);
});
test('handles database operations efficiently', () async {
var stopwatch = Stopwatch()..start();
// Create 1000 records
for (var i = 0; i < 1000; i++) {
await app.post('/users', body: {
'name': 'User $i',
'email': 'user$i@example.com'
});
}
stopwatch.stop();
// Check performance
expect(
stopwatch.elapsedMilliseconds / 1000,
lessThan(50) // Less than 50ms per operation
);
});
});
}
```
### 4. Laravel-Style Feature Tests
```dart
void main() {
group('Feature Tests', () {
late TestCase test;
setUp(() {
test = await TestCase.make();
});
test('user can register', () async {
await test
.post('/register', {
'name': 'John Doe',
'email': 'john@example.com',
'password': 'password',
'password_confirmation': 'password'
})
.assertStatus(302)
.assertRedirect('/home');
test.assertDatabaseHas('users', {
'email': 'john@example.com'
});
});
test('user can login', () async {
// Create user
await test.createUser({
'email': 'john@example.com',
'password': 'password'
});
await test
.post('/login', {
'email': 'john@example.com',
'password': 'password'
})
.assertAuthenticated();
});
});
}
```
## Performance Testing Tools
### 1. WRK Benchmarking
```bash
# Basic load test
wrk -t12 -c400 -d30s http://localhost:8080/api/endpoint
# Test with custom script
wrk -t12 -c400 -d30s -s script.lua http://localhost:8080/api/endpoint
```
### 2. Custom Load Testing
```dart
void main() {
test('load test', () async {
var client = HttpClient();
var stopwatch = Stopwatch()..start();
// Configure test
var duration = Duration(minutes: 1);
var concurrency = 100;
var results = <Duration>[];
// Run test
while (stopwatch.elapsed < duration) {
var requests = List.generate(concurrency, (i) async {
var requestWatch = Stopwatch()..start();
await client.get('localhost', 8080, '/api/endpoint');
requestWatch.stop();
results.add(requestWatch.elapsed);
});
await Future.wait(requests);
}
// Analyze results
var average = results.reduce((a, b) => a + b) ~/ results.length;
var sorted = List.of(results)..sort();
var p95 = sorted[(sorted.length * 0.95).floor()];
var p99 = sorted[(sorted.length * 0.99).floor()];
print('Results:');
print('Average: ${average.inMilliseconds}ms');
print('P95: ${p95.inMilliseconds}ms');
print('P99: ${p99.inMilliseconds}ms');
});
}
```
## Best Practices
### 1. Test Organization
```dart
// Group related tests
group('UserService', () {
group('creation', () {
test('creates valid user', () {});
test('validates input', () {});
test('handles duplicates', () {});
});
group('authentication', () {
test('authenticates valid credentials', () {});
test('rejects invalid credentials', () {});
});
});
```
### 2. Test Data Management
```dart
class TestCase {
// Create test data
Future<User> createUser([Map<String, dynamic>? attributes]) async {
return factory.create(User, attributes);
}
// Clean up after tests
Future<void> cleanup() async {
await database.truncate(['users', 'posts', 'comments']);
}
}
```
### 3. Assertions
```dart
// Use descriptive assertions
expect(user.name, equals('John Doe'),
reason: 'User name should match input');
expect(response.statusCode,
isIn([200, 201]),
reason: 'Response should indicate success'
);
expect(
() => service.validateEmail('invalid'),
throwsA(isA<ValidationException>()),
reason: 'Should reject invalid email'
);
```
## Performance Benchmarks
### 1. Response Time Targets
```yaml
API Endpoints:
- Average: < 100ms
- P95: < 200ms
- P99: < 500ms
Database Operations:
- Simple queries: < 10ms
- Complex queries: < 50ms
- Writes: < 20ms
Cache Operations:
- Reads: < 5ms
- Writes: < 10ms
```
### 2. Throughput Targets
```yaml
API Layer:
- Minimum: 1000 requests/second
- Target: 5000 requests/second
Database Layer:
- Reads: 10000 operations/second
- Writes: 1000 operations/second
Cache Layer:
- Operations: 50000/second
```
### 3. Resource Usage Targets
```yaml
Memory:
- Base: < 100MB
- Under load: < 500MB
- Leak rate: < 1MB/hour
CPU:
- Idle: < 5%
- Average load: < 40%
- Peak load: < 80%
Connections:
- Database: < 100 concurrent
- Cache: < 1000 concurrent
- HTTP: < 10000 concurrent
```
## Next Steps
1. Implement test helpers
2. Add more Laravel-style assertions
3. Create performance test suite
4. Add continuous benchmarking
5. Improve test coverage
Would you like me to:
1. Create more test examples?
2. Add specific performance tests?
3. Create Laravel-compatible test helpers?