Подтвердить что ты не робот

Как запретить ActivityUnitTestCase вызывать Application.onCreate?

Мне, должно быть, что-то не хватает. JavaDoc ActivityUnitTestCase предполагает, что этот тестовый пример проверяет активность в изоляции от системы:

Этот класс обеспечивает изолированное тестирование одного действия. Тестирование активности будет создано с минимальным подключением к системной инфраструктуре, и вы можете вводить издевательские или обернутые версии многих зависимостей активности.

Я предполагал, что включает в себя фактически не запуск приложения. Кроме того, он предоставляет помощник setApplication, который можно использовать, чтобы ввести ложное приложение.

Однако любой ActivityUnitTestCase я запускаю (фактическое) приложение и вызывает его метод onCreate. Точнее, InstrumentationTestRunner, похоже, делает это и делает это еще до того, как я получаю возможность setApplication в методе test setUp! Я даже не заметил этого довольно долгое время, поскольку, похоже, это происходит в момент запуска тестового набора, где даже точки останова Eclipse не достигнуты, но запись в журналы в onCreate показывает, что он действительно вызывался.

Это полностью вне меня. Почему я хочу использовать объект mock app, когда тестовый бегун для Android создает экземпляр и фактически выполняет фактическое приложение? Это еще более проблематично, учитывая, что контролер-бегун работает в своей собственной нити и при этом генерирует основной поток приложений. Это означает, что между выполняемым тестом и условием Application.onCreate возникает условие гонки. Если вы что-то делаете, что может повлиять на ваши тесты, например. записывая в общий файл предпочтений, тогда вы полностью ввернуты, так как ваши тесты будут случайным образом терпеть неудачу.

Я что-то упустил или это просто грубый надзор в тестовой среде?

UPDATE Это, похоже, влияет и на ApplicationTestCase. Прежде чем мой тестовый пример будет запущен, я смогу достичь точки останова в классе приложений onCreate. Мы запускаем Fire-and-забыть AsyncTask там, который будет случайным образом терпеть неудачу, потому что у меня нет возможности издеваться над этим (помните, что до того, как setUp вызывается в моем тестовом примере). Вот трассировка стека, которую я вижу во время этого неясного вызова onCreate:

Thread [<1> main] (Suspended (breakpoint at line 86 in QypeRadar))  
QypeRadar.onCreate() line: 86   
InstrumentationTestRunner(Instrumentation).callApplicationOnCreate(Application) line: 969   
ActivityThread.handleBindApplication(ActivityThread$AppBindData) line: 4244 
ActivityThread.access$3000(ActivityThread, ActivityThread$AppBindData) line: 125    
ActivityThread$H.handleMessage(Message) line: 2071  
ActivityThread$H(Handler).dispatchMessage(Message) line: 99 
Looper.loop() line: 123 
ActivityThread.main(String[]) line: 4627    
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
Method.invoke(Object, Object...) line: 521  
ZygoteInit$MethodAndArgsCaller.run() line: 868  
ZygoteInit.main(String[]) line: 626 
NativeStart.main(String[]) line: not available [native method]  

Почему тестовый бегун callApplicationOnCreate, хотя документы четко заявляет:

Тест-сценарий не будет вызывать onCreate(), пока ваш тестовый вызов не вызовет createApplication(). Это дает вам возможность настроить или настроить любые дополнительные рамки или тестовую логику до onCreate().

Это плоская ложь - это не дает мне шанса!

4b9b3361

Ответ 2

Я делаю тесты с кинжалом, так что, вероятно, это и ваш случай, так как вы, вероятно, хотите просто вводить и не вызывать все, что есть в Application.onCreate, так что это работает отлично для меня (api17 +):

private Context mContext;
private Application mApplication;

@Override
protected void setUp() throws Exception {
    super.setUp();

    mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
        @Override
        public Context getApplicationContext() {
            return mApplication;
        }
    };
    mApplication = new MyAppMock();
    mApplication.attachBaseContext(mContext); 

    setApplication(app);
}

public void testActivityCreated() {
    Intent intent = AboutActivity.createIntent(mContext);
    setActivityContext(mContext);
    startActivity(intent, null, null);
    assertNotNull(getActivity());
}

api16 вам нужно использовать отражение и вызвать Application.attach(context) вместо Application.attachBaseContext(), чтобы установить Application.mLoadedApk, иначе он сработает.

Я собрал все вместе и сделал демонстрационное приложение, которое показывает, как тестировать кинжал: https://github.com/vovkab/dagger-unit-test

Он также показывает, как издеваться над вашим приложением, работает для любой версии Android.