如何使用Robolectric测试Application类?

时间:2014-06-20 04:06:12

标签: android parse-platform robolectric

我正在尝试使用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 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

public class TestParseApplication extends Application

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

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