Как протестировать класс приложения с помощью Robolectric?

Я пытаюсь протестировать push-уведомление с помощью Parse.com с помощью Robolectric. Поскольку инициализация должна выполняться в классе 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)

person Sahil Dave    schedule 20.06.2014    source источник


Ответы (2)


Вы должны обернуть 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);
}

}

Это должно работать, если я не делаю ошибок при наборе текста.

Конечно, это грубая идея. Вместо написания анонимных классов в тестах лучше использовать какую-нибудь mock-библиотеку (мой любимый — Mockito). Пожалуйста, прочтите также об инверсии зависимостей и внедрении (IoC). И, наконец, гораздо лучше отделить тестовое приложение Robolectric от тестовых приложений (пожалуйста, прочтите http://robolectric.blogspot.nl/2013/04/the-test-lifecycle-in-20.html)

person Eugen Martynov    schedule 24.06.2014

public class TestParseApplication extends Application

Это должен быть тестовый набор или набор тестов, а не реальный класс, который вы тестируете.

Для каждого теста необходимо создать экземпляр класса Application. На самом деле, Robolectric сделает это за вас, если вы правильно объявили класс Application в своем манифесте, и вы можете получить текущий экземпляр приложения (с расширенными средствами тестирования) из API robolectric: getShadowApplication().

person S.D.    schedule 24.06.2014