Android Local Unit Tests

Last updated 9 days ago

Android Local Unit Tests

ObjectBox supports local unit tests. This gives you the full ObjectBox functionality for running super fast test directly on your development machine.

On Android, unit tests can either run on an Android device (or emulator), so called instrumented tests, or they can run on your local development machine. Running local unit tests is typically much faster.

To learn how local unit tests for Android work in general have a look at the Android developers documentation on Building Local Unit Tests. Read along to learn how to use ObjectBox in your local unit tests.

Set Up Your Testing Environment

The setup step is only required for ObjectBox 1.4 or older (or if you want to manually add the dependency). In newer versions the ObjectBox plugin automatically adds the native ObjectBox library required for your current operating system.

Add the native ObjectBox library to your existing test dependencies in your app’s build.gradle file:

dependencies {
// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.12'
// Optional -- manually add native ObjectBox library to override auto-detection
testImplementation "io.objectbox:objectbox-linux:$objectboxVersion"
testImplementation "io.objectbox:objectbox-macos:$objectboxVersion"
testImplementation "io.objectbox:objectbox-windows:$objectboxVersion"
}

Local unit tests are currently only supported on 64-bit operating systems.

Note: on Windows you might have to install the Microsoft Visual C++ 2015 Redistributable (x64) packages to use the native library.

Create a Local Unit Test Class

You create your local unit test class as usual under module-name/src/test/java/. To use ObjectBox in your test methods you need to build a BoxStore instance using the generated MyObjectBox class of your project. You can use the directory(File) method on the BoxStore builder to ensure the test database is stored in a specific folder on your machine. To start with a clean database for each test you can delete the existing database using BoxStore.deleteAllFiles(File).

The following example shows how you could implement a local unit test class that uses ObjectBox:

public class NoteTest {
private static final File TEST_DIRECTORY = new File("objectbox-example/test-db");
private BoxStore store;
@Before
public void setUp() throws Exception {
// delete database files before each test to start with a clean database
BoxStore.deleteAllFiles(TEST_DIRECTORY);
store = MyObjectBox.builder()
// add directory flag to change where ObjectBox puts its database files
.directory(TEST_DIRECTORY)
// optional: add debug flags for more detailed ObjectBox log output
.debugFlags(DebugFlags.LOG_QUERIES | DebugFlags.LOG_QUERY_PARAMETERS)
.build();
}
@After
public void tearDown() throws Exception {
if (store != null) {
store.close();
store = null;
}
BoxStore.deleteAllFiles(TEST_DIRECTORY);
}
@Test
public void exampleTest() {
// get a box and use ObjectBox as usual
Box<Note> noteBox = store.boxFor(Note.class);
assertEquals(...);
}
}

Note: To help diagnose issues you can enable log output for ObjectBox actions, such as queries, by specifying one or more debug flags when building BoxStore.

Base class for tests

It’s usually a good idea to extract the setup and tear down methods into a base class for your tests. E.g.:

public abstract class AbstractObjectBoxTest {
protected static final File TEST_DIRECTORY = new File("objectbox-example/test-db");
protected BoxStore store;
@Before
public void setUp() throws Exception {
// delete database files before each test to start with a clean database
BoxStore.deleteAllFiles(TEST_DIRECTORY);
store = MyObjectBox.builder()
// add directory flag to change where ObjectBox puts its database files
.directory(TEST_DIRECTORY)
// optional: add debug flags for more detailed ObjectBox log output
.debugFlags(DebugFlags.LOG_QUERIES | DebugFlags.LOG_QUERY_PARAMETERS)
.build();
}
@After
public void tearDown() throws Exception {
if (store != null) {
store.close();
store = null;
}
BoxStore.deleteAllFiles(TEST_DIRECTORY);
}
}

Testing Entities with Relations

The following is no longer necessary with 1.5 or newer.

To test entities that have relations, like ToOne or ToMany properties, you must modify your entities first. These modifications are normally done by the ObjectBox plugin byte-code transformer. But the transformer does not run for local unit tests (it does for instrumented tests).

For each entity that has relations you need to initialize each ToOne and ToMany field. In addition you need to add a transient BoxStore field named __boxStore.

An example for a modified entity class might look like this:

@Entity
public class Customer {
// normally transformer would add init code, but need to manually for local unit tests
ToOne<Order> lastOrder = new ToOne<>(this, Customer_.lastOrder);
ToMany<Order> orders = new ToMany<>(this, Customer_.orders);
// normally transformer would add field, but need to manually for local unit tests
transient BoxStore __boxStore;
...
}