如何使用Robolectric测试Application类?

9

我正在尝试使用Robolectric测试Parse.com的推送通知。由于初始化必须在Application类中完成,因此我需要进行测试。到目前为止,该应用程序在模拟器上运行良好,但我无法使用Robolectric进行测试。

我的应用程序类的onCreate:

public void onCreate() {
            super.onCreate();

            // Add your initialization code here
            Parse.initialize(this, APP_KEY,
                            CLIENT_ID);

            // Specify an Activity to handle all pushes by default.
            PushService.setDefaultPushCallback(this, MainActivity.class);

            // Save the current Installation to Parse.
            //This is null on test
            android_id = Secure.getString(getApplicationContext()
                            .getContentResolver(), Secure.ANDROID_ID);

            System.out.println("android id >>" + android_id);

            ParseInstallation installation = ParseInstallation
                            .getCurrentInstallation();
            installation.put("UniqueId", android_id);
            installation.saveInBackground();

            ParseUser.enableAutomaticUser();
            ParseACL defaultACL = new ParseACL();

            // If you would like all objects to be private by default, remove this
            // line.
            defaultACL.setPublicReadAccess(true);
            Parse.setLogLevel(Parse.LOG_LEVEL_VERBOSE);
            ParseACL.setDefaultACL(defaultACL, true);
    }

测试

@RunWith(RobolectricTestRunner.class)
public class TestParseApplication extends Application {
private ParseApplication parseApplication;

@Before
public void setup() {

    parseApplication = new ParseApplication();
    parseApplication.android_id = "123";

    Robolectric.application = parseApplication;
}

@Test
public void shouldPass() {
    assertTrue(true);
}

}

堆栈跟踪

WARNING: no system properties value for ro.build.date.utc
android id >>null

java.lang.IllegalArgumentException: Must subscribe to channel with a valid icon identifier.
        at com.parse.PushService.setDefaultPushCallback(PushService.java:298)
        at com.parse.PushService.setDefaultPushCallback(PushService.java:277)
        at com.parse.starter.ParseApplication.onCreate(ParseApplication.java:30)
        at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:164)
        at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:430)
        at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:236)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
        at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
2个回答

7
您应该将Parse API封装到某个类中并进行模拟操作:
public class ParseAPI {
   public void init(Context context, String key, String id) {
        // Add your initialization code here
        Parse.initialize(context, key,
                        id);
   }

   public void initPush(Context context, Class pushCallbackClass) {
        // Specify an Activity to handle all pushes by default.
        PushService.setDefaultPushCallback(context, puchCallbackClass);
   }
}

修改您的应用程序:

public void onCreate() {
    super.onCreate();

    ParseAPI api = getParseAPI();

    api.init(this, APP_KEY, CLIENT_ID)
    api.initPush(this, MainActivity.class);
}

protected ParseAPI getParseAPI() {
    return new ParseAPI();
}

修改您的测试应用程序和测试:

@RunWith(RobolectricTestRunner.class)
public class TestParseApplication extends ParseApplication {
private ParseApplication parseApplication;

@Before
public void setup() {

    parseApplication = new TestParseApplication();
    parseApplication.android_id = "123";

    Robolectric.application = parseApplication;
}

protected ParseAPI getParseAPI() {
    return new ParseAPI() {
               public void init(Context context, String key, String id) {
               }

               public void initPush(Context context, Class pushCallbackClass) {
               }
    };
}

@Test
public void shouldPass() {
    assertTrue(true);
}

}

如果我在打字时没有犯任何错误,这应该可以正常工作。

当然,这只是一个粗略的想法。最好使用一些模拟库来代替在测试中编写匿名类(我最喜欢的是Mockito)。还请阅读有关依赖反转和注入(IoC)的内容。最后,将Robolectric测试应用程序与应用程序测试分开会更好(请阅读http://robolectric.blogspot.nl/2013/04/the-test-lifecycle-in-20.html)。


2
public class TestParseApplication extends Application

这应该是一个测试集或测试套件,而不是您正在测试的实际类。

对于每个测试,您需要实例化Application类。实际上,如果您已经在清单文件中正确声明了Application类,Robolectric会为您执行此操作,并且您可以从robolectric api获取当前应用程序实例(具有增强的测试功能):getShadowApplication()。


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