Правильная очистка / демонтаж после контрольно-измерительных приборов, только когда приложение завершено на 100% - PullRequest
0 голосов
/ 07 января 2019

У меня есть несколько комплексных инструментальных тестов (основанных на Espresso), которые запускают нашу деятельность по запуску, а затем перемещаются по нашему приложению (в конечном итоге создавая несколько действий). В конце каждого теста наш @After аннотированный метод удаления выполняет некоторую очистку.

Проблема, с которой мы столкнулись, заключается в том, что после завершения теста (успешного или неудачного подтверждения) приложение все еще «работает», поэтому некоторая очистка фактически приводит к сбою приложения. Это либо приводит к ложным срабатываниям, если утверждение было успешным, либо скрывает неудачу теста (мы видим только сбой, а не ошибочное утверждение).

Вот пример:

import android.app.Instrumentation;
import android.content.Intent;
import android.preference.PreferenceManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;

import com.example.SplashActivity;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import static android.support.test.InstrumentationRegistry.getInstrumentation;

public class ExampleTest {

    @Rule
    public ActivityTestRule<SplashActivity> splashActivityTestRule
            = new ActivityTestRule<>(SplashActivity.class, true, false);

    Instrumentation.ActivityMonitor splashActivityMonitor;

    @Before
    public void setUp() {
        splashActivityMonitor = new Instrumentation.ActivityMonitor(SplashActivity.class.getName(), null, false);
        getInstrumentation().addMonitor(splashActivityMonitor);
    }

    @Test
    public void someTest() throws Exception {
        // ... other test-specific setup before starting splash activity

        // start first activity
        splashActivityTestRule.launchActivity(new Intent());

        // a bunch of espresso steps that result in several other activities
        // ... creating and adding Instrumentation.ActivityMonitor for each one

        // assert something
    }

    @After
    public void tearDown() {
        // clear shared prefs to prepare for next test
        PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getTargetContext())
                .edit()
                .clear()
                .apply();

        // At this point the app is still running. Maybe a UI is still loading that was not relevant to the test, 
        // or some mock web request is in flight. But at some point after the final assert in our test, the app needs
        // to get something from shared prefs, which we just cleared, so the app crashes.
    }
}

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

Так как я могу утверждать, что приложение мертво и ушло до того, как выполнит эту очистку?

Некоторые возможные (но ужасные) решения, которые я придумала:

После окончательного подтверждения продолжайте возвращаться к некоторой нейтральной точке в приложении (т.е. используйте эспрессо для выхода из системы и возврата к экрану заставки). Это должно работать, но это добавит много других шагов к каждому тесту. Также я не уверен, что это сработает, если не получится подтверждение.

Или выполнить какое-то уничтожение приложения в демонтаже:

public void tearDown() {
    // finish all tasks before cleaning up
    ActivityManager activityManager =
            (ActivityManager) InstrumentationRegistry.getTargetContext().getSystemService(Context.ACTIVITY_SERVICE);

    List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
    for (ActivityManager.AppTask appTask : appTasks) {
        appTask.finishAndRemoveTask();
    }

    // clear shared prefs to prepare for next test
    PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getTargetContext())
            .edit()
            .clear()
            .apply();
}

Обновление:

Я знаю, что могу использовать ActivityTestRule.afterActivityFinished() документы , но я не думаю, что это будет работать для множественных действий.

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Проблема, которую вы описали, может быть решена с помощью AndroidTestOrchestrator. Из официальной документации Android:

При использовании AndroidJUnitRunner версии 1.0 или выше у вас есть доступ на инструмент под названием Android Test Orchestrator, который позволяет запускать каждый из тестов вашего приложения в своем собственном вызове Instrumentation.

Тестируемое приложение будет очищаться после каждого запуска теста автоматически.

build.gradle образец файла с включенным AndroidTestOrchestrator:

  1. Использование AndroidTestOrchestrator с библиотекой поддержки Android - github link
  2. Использование AndroidTestOrchestrator с тестовой библиотекой AndroidX - github link

Официальная документация по Android - ссылка .

0 голосов
/ 10 января 2019

а) можно либо установить предпочтения по умолчанию, а не закрывать их -

b) или использовать сам общий ресурс, чтобы предотвратить состояние гонки:

public static final String PREFERENCE_KEY_TEST_COUNT = "testCount";
public static final int MAX_TEST_COUNT = 6;

@After
public void tearDown() {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getTargetContext()):
    if(prefs.getPreference(PREFERENCE_KEY_TEST_COUNT, 0) >= MAX_TEST_COUNT) {
        prefs.edit().clear().apply();
    } else {
        int testCount = prefs.getPreference(PREFERENCE_KEY_TEST_COUNT, 0) + 1;
        prefs.edit().putInt(PREFERENCE_KEY_TEST_COUNT, testCount).apply();
    }
}

c) или Test Suite и пользовательский Runner может использоваться для управления тестами; этот пример объясняет это.

...