Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instrumental test for Realm database gives "Call 'Realm.init(Context)' before creating Realmconfiguration" even though I call it

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)
like image 762
Wouter Van der Schraelen Avatar asked Oct 29 '22 18:10

Wouter Van der Schraelen


1 Answers

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);
    }
}
like image 133
EpicPandaForce Avatar answered Nov 15 '22 07:11

EpicPandaForce