Docs Menu

Docs HomeDevelop ApplicationsAtlas Device SDKs

Test & Debug - Flutter SDK

On this page

  • Test
  • Test Using an In-Memory Realm
  • Test Using a Default Realm
  • Clean up Realm in Tests
  • Test App Services
  • Test Synced Realms
  • Debug
  • Debug with Realm Studio
  • Debug with DevTools and Code Editors

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.

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.

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:

  1. Lazily instantiate the Realm with the late keyword at a higher scope than your tests

  2. Open the realm with a Configuration.inMemory() inside a setUp function.

  3. 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
}

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
}

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);
});
}

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.provider, AuthProviderType.anonymous);
});
}

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:

  1. Delete all data in the realm.

  2. Sync the latest changes to Atlas to ensure that the deletion propagates to Atlas.

  3. Close the Realm.

  4. 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>());
});
}

Realm Studio enables you to open and edit local realms. It supports Mac, Windows and Linux.

To debug your app, You can use the Realm Flutter SDK with Flutter DevTools.

← Troubleshooting - Flutter SDK