Test & Debug - Flutter SDK
On this page
This page covers some strategies for testing and debugging Flutter apps using the Realm Flutter SDK. You likely will have to adapt the examples on this page significantly to work with your app.
Test
To run tests on the Flutter SDK using the flutter_test and test, you must first run the following command:
dart run realm install
This command installs native binaries needed to run tests for the Flutter app.
Note
Testing on macOS
If you are developing with the Realm Flutter SDK on macOS, network requests do not work by default due to built-in macOS security settings. To fix this, you must change the Flutter app's macOS network entitlements.
To learn how to do this, refer to Use Realm with the macOS App Sandbox.
Note
Testing for Dart Standalone SDK
If you're using the Dart Standalone SDK, you do don't need to install any additional native binaries to run tests. This is because as part of the installation to use the Dart Standalone SDK in an app, you already need to install the native binaries.
Test Using an In-Memory Realm
An easy way to use and test Realm-backed applications is to test using an in-memory realm. This helps avoid overriding application data or leaking state between tests. Note that you cannot use an in-memory realm to test Device Sync. To create an in-memory realm for your tests, you can do the following:
Lazily instantiate the
Realm
with thelate
keyword at a higher scope than your testsOpen the realm with a Configuration.inMemory() inside a setUp function.
Close the realm in a tearDown function.
import 'package:realm/realm.dart'; import 'package:flutter_test/flutter_test.dart'; import '../lib/schema.dart'; // Import schema used in test void main() { late Realm realm; setUp(() { realm = Realm(Configuration.inMemory([Car.schema])); }); tearDown(() { realm.close(); }); // ...rest of test code }
Test Using a Default Realm
Another way to use and test Realm-backed applications is to use the default realm. To avoid overriding application data or leaking state between tests, set the default realm to a new file for each test using Configuration.defaultRealmName inside of a setUp function.
import 'dart:math'; import 'package:realm/realm.dart'; import 'package:flutter_test/flutter_test.dart'; // Utility function to generate random realm name String generateRandomRealmName(int len) { final r = Random(); const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; final nameBase = List.generate(len, (index) => _chars[r.nextInt(_chars.length)]).join(); return '$nameBase.realm'; } void main() { // Set default Realm name before each test setUp(() { Configuration.defaultRealmName = generateRandomRealmName(10); }); // ...rest of test code }
Clean up Realm in Tests
To clean up your tests, you can lazily instantiate the realm with the
late
keyword at a higher scope than your tests. Then run clean up
operations inside of a tearDown function.
Inside of the tearDown
callback function, close and delete the realm
instance.
import 'package:realm/realm.dart'; import 'package:flutter_test/flutter_test.dart'; import '../lib/schema.dart'; // Import schema used in test void main() { late Realm realm; // Close and delete the realm after each test tearDown(() { final path = realm.config.path; realm.close(); Realm.deleteRealm(path); }); test("Open a local realm", () { realm = Realm(Configuration.local([Car.schema])); expect(realm.isClosed, isFalse); }); }
Test App Services
To test how your Flutter app interacts with Atlas App Services, create a separate App Services App with the same configuration as your production app, and connect to it from your test file. To learn more about how to make a copy of the App, refer to Copy an App in the App Services documentation.
You also likely need an authenticated user to test the services that the App exposes. Often, anonymous users are useful for testing.
To test the app, you can lazily instantiate the App
and User
with the late
keyword at a higher scope than your tests. Instantiate
the App
client and log a user in inside a setUp
function. Then
run clean up operations inside of a tearDown function.
Inside of the tearDown
callback function, delete the current user from the backend
and then log them out on the device.
import 'package:realm/realm.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { late App app; setUp(() async { app = App(AppConfiguration(TEST_APP_ID)); await app.logIn(Credentials.anonymous()); }); // Delete and log current user out tearDown(() async { app.deleteUser(app.currentUser!); await app.currentUser?.logOut(); }); test("Check user type", () { final user = app.currentUser!; expect(user.identities[0].provider, AuthProviderType.anonymous); }); }
Test Synced Realms
To test how your Flutter app works with Atlas Device Sync, create a separate App Services App with the same configuration as your production app, and connect to it from your test file. To learn more about how to make a copy of the App, refer to Copy an App in the App Services documentation.
Testing synced realms builds on the Clean up Realm in Tests and Test App Services sections above.
To test a synced Realm, you can lazily instantiate the App
and
Realm
with the late
keyword at a higher scope than your tests.
In a tearDown
function, you should perform the following:
Delete all data in the realm.
Sync the latest changes to Atlas to ensure that the deletion propagates to Atlas.
Close the Realm.
Delete the Realm File from the device.
import 'package:realm/realm.dart'; import 'package:flutter_test/flutter_test.dart'; import '../lib/schema.dart'; // Import schema used in test void main() { late App app; late Realm realm; setUp(() async { app = App(AppConfiguration(TEST_APP_ID)); await app.logIn(Credentials.anonymous()); }); // Log current user out tearDown(() async { // Delete all items in the realm so that the items are not persisted in Atlas // and do not re-sync in subsequent tests. realm.write(() => realm.deleteAll<Car>()); // Fully synchronize realm before closing and deleting await realm.syncSession.waitForDownload(); await realm.syncSession.waitForUpload(); // Get path before realm closed to pass to Realm.deleteRealm() final path = realm.config.path; realm.close(); Realm.deleteRealm(path); await app.currentUser?.logOut(); }); test("Add subscriptions", () async { const subName = 'allDogs'; final user = app.currentUser!; realm = Realm(Configuration.flexibleSync(user, [Car.schema])); realm.subscriptions.update((mutableSubscriptions) { mutableSubscriptions.add(realm.all<Car>(), name: subName); }); await realm.subscriptions.waitForSynchronization(); expect(realm.subscriptions.findByName(subName), isA<Subscription>()); }); }
Debug
Debug with Realm Studio
Realm Studio enables you to open and edit local realms. It supports Mac, Windows and Linux.
Debug with DevTools and Code Editors
To debug your app, You can use the Realm Flutter SDK with Flutter DevTools.