使用SugarORM和Robolectric进行测试

3
我正在为我的Android项目建立测试环境。基本的Robolectric设置已经完成。我使用了这个不错的教程。如果我在Manifest.xml中注释掉SugarORM,所有的测试都可以正常工作。但是,如果我想要使用它和SugarORM一起使用,我总是会得到这个错误:
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)
每个人都有同样的问题吗?
编辑:
也许是因为Robolectric在测试后关闭,并且sugarorm仍未完成。我的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);

    }

}

编辑2.0:

为了使Robolectric能够找到android:name=com.orm.SugarApp,您需要创建一个与com.orm相同的包名的测试文件夹,并添加一个名为TestSugarApp的测试类。然后,您就可以测试所有这些内容。

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");
    }
}

你的App类中有特殊的代码在onTerminate方法里吗? - Eugen Martynov
我在activity中只有一个ondestroy。sugarorm是在应用程序之前加载的。因为我将application android:name设置为sugarorm。 - loose11
1
这个问题的解决方案在1.4测试版中。 - David
2个回答

5
好的,请尝试下一步。在你的测试代码中添加下一个类:
public class TestSugarApp
    extends SugarApp
{
    @Override
    public void onCreate() {}

    @Override
    public void onTerminate() {}
}

名为Test的类将被Robolectric加载和使用,您可以覆盖一些与测试无关的内容。我试图防止在onCreate和onTerminate中执行SugarApp中的代码(https://github.com/satyan/sugar/blob/master/library/src/com/orm/SugarApp.java)。


谢谢。我尝试了,但程序崩溃了。我解决了这个问题。 :) 请看第一篇帖子 :) - loose11
如果是这样,请接受答案。你真的想在这个课程中进行测试吗? - Eugen Martynov
3
您无需将测试文件置为空,也可以移除@RunWith@Config以及测试本身。Robolectric会找到您的测试应用程序类并加载它。http://robolectric.blogspot.nl/2013/04/the-test-lifecycle-in-20.html - Eugen Martynov

1
@Eugen Martynov的答案非常完美(非常感谢!)。然而,当您自己扩展android.app.Application时(它又扩展了SugarApp),那么您也将排除自己的代码。
我已经使用以下代码解决了这个问题:
测试代码中的Application类(与Eugen的答案相反):
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;
    }
}

我自己的应用程序类(扩展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
    }
}

我同意它看起来不太美观(有什么建议可以让它更好看吗?),但对我来说它完美地工作!
附注:我在清单文件中像这样声明了我的应用程序类:
<application
    android:name=".App"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接