Navigation

Testing - Android SDK

On this page

  • Integration Tests
  • Application Context
  • Looper Thread
  • Delay Test Execution While Async Calls Complete
  • Testing Backend
  • Testing Atlas Cluster
  • Full Example
  • Unit Tests
  • Full Example

You can test your application using unit tests or integration tests. Unit tests only assess the logic written in your application's code. Integration tests assess your application logic, database queries and writes, and calls to your application's backend, if you have one. Unit tests run on your development machine using the JVM, while integration tests run on a physical or emulated Android device. You can run integration tests by communicating with actual instances of Realm Database or a Realm app backend using Android's built-in instrumented tests.

Android uses specific file paths and folder names in Android projects for unit tests and instrumented tests:

Test Type
Path
Unit Tests
/app/src/test
Instrumented Tests
/app/src/androidTest

Because the SDK uses C++ code via Android Native for data storage, unit testing requires you to entirely mock interactions with Realm Database. Prefer integration tests for logic that requires extensive interaction with the database.

This section shows how to integration test an application that uses the Realm SDK. It covers the following concepts in the test environment:

  • acquiring an application context
  • executing logic on a Looper thread
  • how to delay test execution while asynchronous method calls complete

Applications that use Realm Sync or a backend Realm app also require (not covered here):

  • a separate Realm app backend for testing, with separate user accounts and data
  • a separate Atlas cluster containing test-only data

To initialize the SDK, you'll need to provide an application or activity context. This isn't available by default in Android integration tests. However, you can use Android's built-in testing ActivityScenario class to start an activity in your tests. You can use any activity from your application, or you can create an empty activity just for testing. Call ActivityScenario.launch() with your activity class as a parameter to start the simulated activity.

Next, use the ActivityScenario.onActivity() method to run a lambda on the simulated activity's main thread. In this lambda, you should call the Realm.init() function to initialize the SDK with your activity as a parameter. Additionally, you should save the parameter passed to your lambda (the newly created instance of your activity) for future use.

Because the onActivity() method runs on a different thread, you should block your test from executing further until this initial setup completes.

The following example uses an ActivityScenario, an empty testing activity, and a CountDownLatch to demonstrate how to set up an environment where you can test your Realm application:

Realm Database functionality such as Live objects and change notifications only work on Looper threads. Threads configured with a Looper object pass events over a message loop coordinated by the Looper. Test functions normally don't have a Looper object, and configuring one to work in your tests can be very error-prone.

Instead, you can use the Activity.runOnUiThread() method of your test activity to execute logic on a thread that already has a Looper configured. Combine Activity.runOnUiThread() with a CountDownLatch as described in the delay section to prevent your test from completing and exiting before your logic has executed. Within the runOnUiThread() call, you can interact with the SDK just like you normally would in your application code:

Because the SDK uses asynchronous calls for common operations such as database queries, authentication, and function calls, tests need a way to wait for those async calls to complete. Otherwise, your tests will exit before your asynchronous (or multi-threaded) calls run. This example uses Java's built-in CountDownLatch. Follow these steps to use a CountDownLatch in your own tests:

  1. Instantiate a CountDownLatch with a count of 1.
  2. After running the async logic your test needs to wait for, call that CountDownLatch instance's countDown() method.
  3. When you need to wait for async logic, add a try/catch block that handles an InterruptedException. In that block, call that CountDownLatch instance's await() method.
  4. Pass a timeout interval and unit to await(), and wrap the call in a Assert.assertTrue() assertion. If the logic takes too long, the await() call times out, returning false and failing the test.

The following example demonstrates the use of a CountDownLatch to wait for authentication and opening a realm asynchronously on a separate thread:

Applications that use a Realm app backend should not connect to the production backend for testing purposes for the following reasons:

  • you should always keep test users and production users separate for security and privacy reasons
  • tests often require a clean initial state, so there's a good chance your tests will include a setup or teardown method that deletes all users or large chunks of data

You can use environments to manage separate apps for testing and production.

Applications that use Realm Sync or MongoDB queries may read, write, update, or delete data stored in connected Atlas clusters. For security purposes, you shouldn't store production data and testing data on the same cluster. Additionally, tests may require schema changes before those changes are gracefully handled in your production application. As a result, you should use a separate Atlas cluster when testing your application.

The following example shows a full Junit instrumented androidTest example running Realm Database in integration tests:

Tip
See also:

See the Realm Documentation Examples App for an example of integration testing the SDK locally and with a live backend.

To unit test Realm applications that use Realm, you must mock Realm Database (and your application backend, if you use one). Use the following libraries to mock SDK functionality:

To make these libraries available for unit testing in your Android project, add the following to the dependencies block of your application build.gradle file:

testImplementation "org.robolectric:robolectric:4.1"
testImplementation "org.mockito:mockito-core:3.3.3"
testImplementation "org.powermock:powermock-module-junit4:2.0.9"
testImplementation "org.powermock:powermock-module-junit4-rule:2.0.9"
testImplementation "org.powermock:powermock-api-mockito2:2.0.9"
testImplementation "org.powermock:powermock-classloading-xstream:2.0.9"
Note
Version Compatibility

Mocking the SDK in unit tests requires Robolectric, Mockito, and Powermock because the SDK uses Android Native C++ method calls to interact with Realm Database. Because the frameworks required to override these method calls can be delicate, you should use the versions listed above to ensure that your mocking is successful. Some recent version updates (particularly Robolectric version 4.2+) can break compiliation of unit tests using the SDK.

To configure your unit tests to use Robolectric, PowerMock, and Mockito with the SDK, add the following annotations to each unit test class that mocks the SDK:

Then, bootstrap Powermock globally in the test class:

Next, mock the components of the SDK that might query native C++ code so we don't hit the limitations of the test environment:

Once you've completed the setup required for mocking, you can start mocking components and wiring up behavior for your tests. You can also configure PowerMockito to return specific objects when new objects of a type are instantiated, so even code that references the default realm in your application won't break your tests:

After mocking a realm, you'll have to configure data for your test cases. See the full example below for some examples of how you can provide testing data in unit tests.

The following example shows a full JUnit test example mocking Realm Database in unit tests. This example tests an activity that performs some basic Realm Database operations. The tests use mocking to simulate those operations when that activity is started during a unit test:

Tip
See also:

See the Unit Testing Example App for an example of unit testing an application that uses Realm.

Give Feedback

On this page

  • Integration Tests
  • Application Context
  • Looper Thread
  • Delay Test Execution While Async Calls Complete
  • Testing Backend
  • Testing Atlas Cluster
  • Full Example
  • Unit Tests
  • Full Example