简体   繁体   English

如何使用Robolectric测试Application类?

[英]How to test Application class with Robolectric?

I am trying to test push notification with Parse.com using Robolectric. 我正在尝试使用Robolectric测试Parse.com的推送通知。 As the initialization has to be done in an Application class, I need to test it. 由于初始化必须在Application类中完成,我需要对其进行测试。 So far, the app is working fine on emulator but I am not able to test it with Robolectric. 到目前为止,该应用程序在模拟器上运行良好,但我无法使用Robolectric进行测试。

My onCreate of application class: 我的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);
    }

Test 测试

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

}

StackTrace 堆栈跟踪

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)

You should wrap Parse API to some class and mock it: 你应该将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);
   }
}

Modify your app: 修改您的应用:

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

Modify your test app and tests: 修改您的测试应用和测试:

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

}

This should work if I don't make any error while typing. 如果我在键入时没有出现任何错误,这应该有效。

Of course this is rough idea. 当然这是个粗略的想法。 It is better to use some mock library instead of writing anonymous classes in tests (My favourite is Mockito ). 最好使用一些模拟库而不是在测试中编写匿名类(我最喜欢的是Mockito )。 Please also read about dependency inversion and injection ( IoC ). 还请阅读依赖性反转和注入( IoC )。 And last it is much better to separate Robolectric test application from application tests (please read http://robolectric.blogspot.nl/2013/04/the-test-lifecycle-in-20.html ) 最后将Robolectric测试应用与应用测试分开要好得多(请参阅http://robolectric.blogspot.nl/2013/04/the-test-lifecycle-in-20.html

public class TestParseApplication extends Application

This should be a test set or a test suite, not the actual class you are testing. 这应该是测试集或测试套件,而不是您正在测试的实际类。

For each test, you need to instantiate the Application class. 对于每个测试,您需要实例化Application类。 Actually, Robolectric does that for you if you have properly declared Application class in your manifest, and you can get current application instance (with enhanced testing facilities) from robolectric api: getShadowApplication(). 实际上,如果您在清单中正确声明了Application类,Robolectric会为您执行此操作,并且您可以从robolectric api:getShadowApplication()获取当前应用程序实例(具有增强的测试功能)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM