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

Как определить, запущено ли приложение Android с помощью инструментария тестирования JUnit?

Мне нужно определить во время выполнения из кода, если приложение запускается в TestInstrumentation.

Я мог бы инициализировать тестовую среду с помощью некоторой переменной env/system, но конфигурация запуска Eclipse ADK не позволила бы мне это сделать.

Стандартные свойства и окружающая среда Android не имеют никаких данных об этом. Более того, они одинаково одинаковы, независимо от того, запускается ли приложение регулярно или тестируется.

Это может быть решение: Можно ли узнать, работает ли приложение Android как часть контрольного теста, но поскольку я не тестирую действия, все предлагаемые методы там не сработают. Этот метод ActivityManager.isRunningInTestHarness() использует это под капотом:

SystemProperties.getBoolean("ro.test_harness") 

который всегда возвращает false в моем случае. (Для работы со скрытым классом android.os.SystemProperties я использую отражение).

Что еще я могу сделать, чтобы попытаться определить внутри приложения, если он находится под тестированием?

4b9b3361

Ответ 1

Я нашел одно хакерское решение: из приложения можно попробовать загрузить класс из тестового пакета. Аппликационный загрузчик классов неожиданно может загружать классы по имени из проекта тестирования, если он был запущен под тестированием. В другом случае класс не найден.

private static boolean isTestMode() {
  boolean result;
  try {
    application.getClassLoader().loadClass("foo.bar.test.SomeTest");
    // alternatively (see the comment below):
    // Class.forName("foo.bar.test.SomeTest");
    result = true;
  } catch (final Exception e) {
result = false;
  }
  return result;
}

Я признаю, что это не изящно, но это работает. Будем благодарны за правильное решение.

Ответ 2

Решение isTestMode() не работает для меня на Android Studio 1.2.1.1. Всемогущий Krzysztof из нашей компании изменил ваш метод, используя:

Class.forName("foo.bar.test.SomeTest");

вместо getClassLoader(). Спасибо за Krzysztof!

Ответ 3

Мы создали решение для передачи параметров MainActivity и используем его внутри метода onCreate, позволяя вам определить, как будет создана Activity.

В классе MainActivity мы создали некоторые константы, которые также могут быть перечислением. Мы также создали статический атрибут.

public class MainActivity {
    public static final int APPLICATION_MODE = 5;
    public static final int UNIT_TEST_MODE = 10;
    public static final int OTHER_MODE = 15;

    public static int activityMode = APPLICATION_MODE;
    (...)

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        switch (activityMode) {
            case OTHER_MODE:
                (...)
                break;

            case UNIT_TEST_MODE:
                Log.d(TAG, "Is in Test Mode!");
                break;

            case APPLICATION_MODE:
                (...)
                break;
        }
        (...)
    }
    (...)
}

Мы сделали абстракцию класса MainActivityTest, создали setApplicationMode и вызвали этот метод внутри метода setUp(), прежде чем вызывать метод super.setUp().

public abstract class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {

    protected void setUp() throws Exception {
        setApplicationMode();  // <=====
        super.setUp();
        getActivity();
        (...)
    }

    (...)
    public void setApplicationMode() {
        MainActivity.activityMode = MainActivity.UNIT_TEST_MODE;
    }
}

Все остальные классы тестов наследуют от MainActivityTest, если мы хотим, чтобы у него было другое поведение, мы можем просто переопределить метод setApplicationMode.

public class OtherMainActivityTest extends MainActivityTest {
    (...)
    @Override
    public void setApplicationMode() {
        MainActivity.activityMode = MainActivity.OTHER_MODE;
    }
}

Пользователь nathan-almeida является соавтором этого решения.