# Database Testing - [Introduction](#introduction) - [Using In-Memory Database](#using-in-memory-database) - [Running Migrations](#running-migrations) - [Using Factories](#using-factories) - [Model Testing](#model-testing) - [Database Assertions](#database-assertions) - [Refreshing Database](#refreshing-database) ## Introduction Magic makes it easy to test database interactions using in-memory SQLite databases and model factories. Tests run fast because the database lives entirely in memory and is recreated fresh for each test. ## Using In-Memory Database Configure your tests to use an in-memory database: ```dart // test/test_helper.dart import 'package:flutter_test/flutter_test.dart'; import 'package:magic/magic.dart'; Future setupTestDatabase() async { await Magic.init( envFileName: '.env.testing', configFactories: [ () => testDatabaseConfig, ], ); } Map get testDatabaseConfig => { 'database': { 'default': 'sqlite', 'connections': { 'sqlite': { 'driver': 'sqlite', 'database': ':memory:', // In-memory database }, }, }, }; ``` ## Running Migrations Run migrations before your tests: ```dart void main() { setUpAll(() async { await setupTestDatabase(); // Run all migrations await Migrator().run([ CreateUsersTable(), CreatePostsTable(), CreateCommentsTable(), ]); }); // Your tests here } ``` ### Fresh Database Per Test For isolation, reset the database for each test: ```dart void main() { setUp(() async { await setupTestDatabase(); await Migrator().fresh([ // Drops all tables and re-runs migrations CreateUsersTable(), CreatePostsTable(), ]); }); test('creates user', () async { // Database is fresh for each test }); } ``` ## Using Factories Use factories to create test data: ```dart test('creates users with factory', () async { // Create 10 users final users = await UserFactory().count(10).create(); expect(users.length, equals(10)); expect(users.first.id, isNotNull); }); test('creates user with specific attributes', () async { final admin = (await UserFactory() .state({'role': 'admin', 'is_active': true}) .create()) .first; expect(admin.role, equals('admin')); expect(admin.isActive, isTrue); }); test('uses factory states', () async { final unverifiedUsers = await UserFactory() .unverified() .count(5) .create(); for (final user in unverifiedUsers) { expect(user.emailVerifiedAt, isNull); } }); ``` ## Model Testing ### Testing CRUD Operations ```dart group('User Model', () { test('creates user', () async { final user = User() ..fill({ 'name': 'John Doe', 'email': 'john@example.com', }); await user.save(); expect(user.id, isNotNull); expect(user.createdAt, isNotNull); }); test('finds user by id', () async { final created = (await UserFactory().create()).first; final found = await User.find(created.id); expect(found, isNotNull); expect(found!.id, equals(created.id)); }); test('updates user', () async { final user = (await UserFactory().create()).first; user.name = 'Updated Name'; await user.save(); final fresh = await User.find(user.id); expect(fresh!.name, equals('Updated Name')); }); test('deletes user', () async { final user = (await UserFactory().create()).first; final id = user.id; await user.delete(); final found = await User.find(id); expect(found, isNull); }); }); ``` ### Testing Relationships ```dart test('user has many posts', () async { final user = (await UserFactory().create()).first; await PostFactory() .state({'user_id': user.id}) .count(3) .create(); final posts = await user.posts(); expect(posts.length, equals(3)); }); ``` ## Database Assertions ### Assert Record Exists ```dart test('creates record in database', () async { await UserFactory().state({'email': 'test@example.com'}).create(); final exists = await DB.table('users') .where('email', 'test@example.com') .exists(); expect(exists, isTrue); }); ``` ### Assert Record Count ```dart test('seeds correct number of users', () async { await UserFactory().count(5).create(); final count = await DB.table('users').count(); expect(count, equals(5)); }); ``` ### Assert Record Deleted ```dart test('deletes user from database', () async { final user = (await UserFactory().create()).first; await user.delete(); final exists = await DB.table('users') .where('id', user.id) .exists(); expect(exists, isFalse); }); ``` ### Assert Specific Values ```dart test('updates user attributes', () async { final user = (await UserFactory().create()).first; user.name = 'New Name'; await user.save(); final row = await DB.table('users') .where('id', user.id) .first(); expect(row?['name'], equals('New Name')); }); ``` ## Refreshing Database ### Between Test Groups ```dart void main() { group('User Tests', () { setUpAll(() async { await setupTestDatabase(); await Migrator().run([CreateUsersTable()]); }); setUp(() async { // Clear users table before each test await DB.table('users').delete(); }); test('test 1', () async { /* ... */ }); test('test 2', () async { /* ... */ }); }); } ``` ### Using Transactions Roll back database changes after each test: ```dart void main() { setUp(() async { DB.beginTransaction(); }); tearDown(() async { DB.rollback(); // Undo all changes }); test('creates user (rolled back)', () async { await UserFactory().create(); // Changes are rolled back after test }); } ``` > [!TIP] > Use `:memory:` database and transactions for the fastest test execution. Each test runs in isolation without persisting data.