Как определить, запущено ли приложение Android с помощью инструментария тестирования JUnit?
Мне нужно определить во время выполнения из кода, если приложение запускается в TestInstrumentation.
Я мог бы инициализировать тестовую среду с помощью некоторой переменной env/system, но конфигурация запуска Eclipse ADK не позволила бы мне это сделать.
Стандартные свойства и окружающая среда Android не имеют никаких данных об этом. Более того, они одинаково одинаковы, независимо от того, запускается ли приложение регулярно или тестируется.
Это может быть решение: Можно ли узнать, работает ли приложение Android как часть контрольного теста, но поскольку я не тестирую действия, все предлагаемые методы там не сработают. Этот метод ActivityManager.isRunningInTestHarness() использует это под капотом:
SystemProperties.getBoolean("ro.test_harness")
который всегда возвращает false в моем случае. (Для работы со скрытым классом android.os.SystemProperties я использую отражение).
Что еще я могу сделать, чтобы попытаться определить внутри приложения, если он находится под тестированием?
Ответы
Ответ 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 является соавтором этого решения.