Testing with SugarORM and Robolectric
Asked Answered
M

2

3

I trying to setup an testing environment for my android project. The basic Robolectric setup is done. I used this nice tutorial. If I comment out SugarORM in my Manifest.xml, all test works fine. But If I want to use it with SugarORM I always get this error:

java.lang.NullPointerException at dalvik.system.DexFile$DFEnum.hasMoreElements(DexFile.java:239) at com.orm.SugarDb.getDomainClasses(SugarDb.java:37) at com.orm.SugarDb.createDatabase(SugarDb.java:104) at com.orm.SugarDb.onCreate(SugarDb.java:100) at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252) at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164) at com.orm.Database.getDB(Database.java:18) at com.orm.SugarApp.onTerminate(SugarApp.java:16) at org.robolectric.internal.ParallelUniverse.tearDownApplication(ParallelUniverse.java:133) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:246) 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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:158) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Does everyone have the same problem?

Edit

Maybe it is, because Robolectric shutdown after the test and sugarorm is still not finished. My TestClass

@RunWith(RobolectricTestRunner.class)
@Config(manifest="./src/main/AndroidManifest.xml",emulateSdk=18)
public class MyActivityTest{

    private ActivityController<OnLogActivity> controller = Robolectric.buildActivity(OnLogActivity.class).create().setup();

    @Test
    public void clickingLogin_shouldStartLoginActivity() {
        OnLogActivity activity = controller.get();
        assertTrue(activity.findViewById(R.id.login) instanceof Button);

    }

}

Edit 2.0:

That Robolectric can find the android:name=com.orm.SugarApp you have to create a testfolder with the same package of com.orm and add a test class called TestSugarApp. After that you can test all the stuff.

package com.orm;

...

@RunWith(RobolectricTestRunner.class)
@Config(manifest="./src/main/AndroidManifest.xml",emulateSdk=18)
public class TestSugarApp extends Application
        implements TestLifecycleApplication {

    private ActivityController<OnLogActivity> controller;


    @Test
    public void startEverTestSugarAppAsFirst() {

    }

    @Override
    public void beforeTest(Method method) {
        Log.v("test", "beforeTest");
    }

    @Override
    public void prepareTest(Object test) {
        Log.v("test", "prepareTest");
    }

    @Override
    public void afterTest(Method method) {
        Log.v("test", "afterTest");
    }
}
Mojica answered 15/1, 2015 at 13:35 Comment(3)
Do you have special code in your App class onTerminate?Benilda
I have only a ondestroy in the activity. The sugarorm is load right before the app. Because I set the application android:name to sugarormMojica
The fix for this is in the 1.4 beta releaseJackstraw
B
5

Ok try next. Add next class to you test code:

public class TestSugarApp
    extends SugarApp
{
    @Override
    public void onCreate() {}

    @Override
    public void onTerminate() {}
}

The class named Test will be loaded and used by Robolectric and you can override some things that are not relevant for testing. I'm trying to prevent to execute code from SugarApp in onCreate and onTerminate (https://github.com/satyan/sugar/blob/master/library/src/com/orm/SugarApp.java).

Benilda answered 18/1, 2015 at 18:3 Comment(3)
Thanks. I tried it, but the program crashed. I solved the problem. :) Have a look to the first post :)Mojica
If so please accept the answer. Do you really want to have test there (in this class)?Benilda
You don't need to have empty test, you can also remove @RunWith, @Config and test itself. Robolectric will find your test app class an load it robolectric.blogspot.nl/2013/04/the-test-lifecycle-in-20.htmlBenilda
R
1

@Eugen Martynov's answer works perfectly (thanks alot!). However, when you've extended android.app.Application yourself (which on its turn extends SugarApp), then you'll also exclude your own code.

I've solved this with using this code:

The Application class in the test code (as opposed to Eugen's answer):

public class TestApp extends App {
    /** Prevents onCreate() and onTerminate() to call their super (in which {@link com.orm.SugarApp} is initialized) */
    @Override
    protected boolean callSuper() {
        return false;
    }
}

My own Application class (extending SugarApp):

public class App extends com.orm.SugarApp {
    private static Context context;

    public static Context getContext() {
        return context;
    }

    @Override
    public void onCreate() {
        if (callSuper()) {
            super.onCreate();
        }

        // My own code is always executed, also during unittests
        context = getApplicationContext();
    }

    @Override
    public void onTerminate() {
        if (callSuper()) {
            super.onTerminate();
        }
    }

    protected boolean callSuper() {
        return true; // Super is executed by default
    }
}

I agree it doesn't look very beautiful (any advice to make this better?), but it works perfectly for me!

ps. I declared my application class in my manifest like this:

<application
    android:name=".App"
Rossie answered 7/6, 2017 at 19:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.