Patterns applied when writing Serverpod backend integration tests.
Directory Structure#
backend/kobic_server/test/
âââ integration/
â âââ helpers/
â â âââ test_auth_helper.dart # Authenticated session creation
â â âââ test_data_factory.dart # Test data creation/cleanup
â â âââ test_scope_helper.dart # Multi-tenant scope validation
â âââ payments/ # Payment endpoint tests
â âââ books/ # Book endpoint tests
â âââ test_tools/
â â âââ serverpod_test_tools.dart # Serverpod auto-generated
â âââ {feature}_test.dart # Other integration tests
âââ unit/
âââ {feature}/ # Service unit tests
Test Levels#
| Level | Purpose | Complexity |
|---|---|---|
| L1 Smoke | Verify authentication requirement | Low |
| L2 Happy Path | Core method normal operation | Medium |
| L3 Comprehensive | Edge cases + security | High |
L1 Smoke Test Pattern#
Verifies that ServerpodUnauthenticatedException is thrown when called without authentication.
import 'package:test/test.dart';
import '../test_tools/serverpod_test_tools.dart';
void main() {
withServerpod('Given MyEndpoint endpoint', (sessionBuilder, endpoints) {
group('L1 Smoke: Exception when called without auth', () {
test('myMethod requires auth', () async {
await expectLater(
endpoints.myEndpoint.myMethod(sessionBuilder),
throwsA(isA<ServerpodUnauthenticatedException>()),
);
});
});
});
}
L2 Happy Path Pattern#
Creates an authenticated session with TestAuthHelper and tests core logic.
import 'package:test/test.dart';
import '../helpers/test_auth_helper.dart';
import '../test_tools/serverpod_test_tools.dart';
void main() {
withServerpod('Given MyEndpoint endpoint', (sessionBuilder, endpoints) {
group('L2 Happy Path: Authenticated user normal operation', () {
test('myMethod returns expected result', () async {
final auth = await TestAuthHelper.createAdminSession(sessionBuilder);
try {
final result = await endpoints.myEndpoint.myMethod(sessionBuilder);
expect(result, isNotNull);
} finally {
await TestAuthHelper.cleanup(
auth.session,
userInfo: auth.userInfo,
);
}
});
});
});
}
TestAuthHelper Usage#
// Admin session
final admin = await TestAuthHelper.createAdminSession(sessionBuilder);
// Publisher session
final publisher = await TestAuthHelper.createPublisherSession(
sessionBuilder,
publisherId: 42,
);
// Regular user session
final user = await TestAuthHelper.createUserSession(sessionBuilder);
// Unauthenticated session
final session = TestAuthHelper.createUnauthenticatedSession(sessionBuilder);
// Cleanup (call in finally block)
await TestAuthHelper.cleanup(admin.session, userInfo: admin.userInfo);
TestDataFactory Usage#
final factory = TestDataFactory(session);
// Create test data + register cleanup callback
factory.onCleanup(() async {
await MyModel.db.deleteRow(session, createdRow);
});
// Clean up all data in reverse order
await factory.cleanup();
Key Rules#
-
Use
sessionBuilder: Endpoint methods receivesessionBuilder(not session) - Auth setup: Set AuthenticationInfo via
session.updateAuthenticated() - Cleanup required: Clean up created data and sessions in finally blocks
-
Direct DB access: Use
UserInfo.db.insertRow(),UserInfo.db.deleteRow()patterns - Unique identifiers: Use
TestDataFactory.uniqueId('prefix')
Related Files#
backend/kobic_server/test/integration/helpers/test_auth_helper.dartbackend/kobic_server/test/integration/helpers/test_data_factory.dartbackend/kobic_server/test/integration/helpers/test_scope_helper.dartdocs/architecture-test-coverage-initiative-2026-03-13.md