For my Android application I use the Realm mobile database. I want to write tests for this, and the best way I found of testing was using instrumental tests.
This is the constructor of my database class:
public Database(Context context) {
this.context = context.getApplicationContext();
Realm.init(context);
RealmConfiguration realmConfig = new RealmConfiguration.Builder()
.name("com.arnowouter.badger.realmdatabase") // TODO: 4/10/2016 check if encryptable
.build();
realm = Realm.getInstance(realmConfig);
}
As you can see, Realm.init(context) is called. But when I run this test:
@RunWith(AndroidJUnit4.class)
@MediumTest
public class DatabaseTest {
Database database;
Context context;
@Before
public void setupDatabase() {
context = InstrumentationRegistry.getContext();
database = new Database(context);
}
}
I get this error:
java.lang.IllegalStateException: Call `Realm.init(Context)` before creating a RealmConfiguration
at io.realm.RealmConfiguration$Builder.<init>(RealmConfiguration.java:399)
at io.realm.RealmConfiguration$Builder.<init>(RealmConfiguration.java:394)
at com.arnowouter.badger.Database.Database.<init>(Database.java:38)
at com.arnowouter.badger.DatabaseTest.setupDatabase(DatabaseTest.java:27)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1970)
Considering the fact that the Context stored in Realm is the application configuration like this
// Thread pool for all async operations (Query & transaction)
volatile static Context applicationContext;
Which is initialized like this
public static synchronized void init(Context context) {
if (BaseRealm.applicationContext == null) {
if (context == null) {
throw new IllegalArgumentException("Non-null context required.");
}
RealmCore.loadLibrary(context);
//...
BaseRealm.applicationContext = context.getApplicationContext();
}
}
This means that the context
you give it returns null
for context.getApplicationContext()
.
Unfortunately, apparently the instrumentation's context returns null
for getFilesDir()
, so we need to obtain an application or an activity context.
I'd probably just set application in a static variable, and use that.
public class CustomApplication extends Application {
private static CustomApplication INSTANCE;
public static CustomApplication get() {
return INSTANCE;
}
@Override
public void onCreate() {
if(INSTANCE == null) {
INSTANCE = this;
}
}
}
And in manifest:
<application name=".CustomApplication"
That way you can do:
@RunWith(AndroidJUnit4.class)
@MediumTest
public class DatabaseTest {
Database database;
Context context;
@Before
public void setupDatabase() {
Realm.init(CustomApplication.get());
context = InstrumentationRegistry.getContext();
database = new Database(context);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With