Intereting Posts
Холст Android: нарисовать прозрачный круг на изображении Robojuice / Butterknife @InjectView Проблема автоформации в Android Studio Отладка собственного кода в android при eclipse не выполняется Как написать уведомление, которое абсолютно ничего не делает при нажатии? Как подключить источник к android.jar Приложение не установлено для этого пользователя Не удалось создать приложение com.android.tools.fd.runtime.BootstrapApplication? Как изменить размер шрифта tabhost в android Запуск автономной библиотеки на Android L. Ошибка: поддерживаются только независимые исполняемые файлы (PIE) Поиск верхнего смещения первого видимого элемента в RecyclerView Android ViewGroup: что мне делать в переопределении onLayout ()? Открытие почтового клиента при нажатии кнопки Преобразование String в LatLng Ожидание разделителя пути класса ';' Перед '\ Android \ android-sdk \ build-tools \ 23.0.1 \ lib \ shrinkedAndroid.jar' в аргументе номер 8 Android: запретить несколько событий onClick на кнопке (которая была отключена)

Как точно настраиваемые объекты Shadow работают в Robolectric?

Если я напишу пользовательский тень для моей активности и зарегистрирую ее с помощью RobolectricTestRunner, будет ли инфраструктура перехватывать Activity с моей пользовательской Shadow всякий раз, когда она запускается?

Благодарю.

Solutions Collecting From Web of "Как точно настраиваемые объекты Shadow работают в Robolectric?"

Короткий ответ: нет.

Robolectric избирает, какие классы он перехватывает, и инструменты. На момент написания этой статьи единственными классами, которые будут задействованы, должно быть полное имя класса, соответствующее одному из этих селекторов:

android.* com.google.android.maps.* org.apache.http.impl.client.DefaultRequestDirector 

Вся причина существования Robolectric заключается в том, что классы, предусмотренные в jQuery Android SDK, исключают исключения при вызове в JVM (т. Е. Не на эмуляторе или устройстве). Активность вашего приложения имеет источник, который не является «враждебным» (он, вероятно, не генерирует исключений при вызове методов или конструкторов). Цель Robolectric – дать вам возможность проверить код приложения, который в противном случае был бы невозможным из-за того, как написан SDK. Некоторые из других причин, почему Robolectric был создан:

  • SDK не всегда имеет методы, позволяющие запрашивать состояние объектов Android, управляемых кодом вашего приложения. Тени могут быть записаны для обеспечения доступа к этому состоянию.
  • Многие из классов и методов в Android SDK являются окончательными и / или частными или защищенными, что затрудняет создание зависимостей, необходимых вашему программному коду, которые в противном случае были бы доступны для вашего кода приложения.

Код может быть явно изменен для теневого класса. В прошлом были разговоры о том, как извлечь функции затенения в автономную библиотеку, чтобы помочь в написании тестов с использованием другого тестового враждебного api.

Почему вы хотите скрыть свою активность?

Это существенно изменилось с помощью Robolectric 2. Вы можете указать пользовательские тени в конфигурации вместо написания собственного TestRunner.

Например:

 @Config(shadows = {ShadowAudioManager.class, ShadowContextWrapper.class}) 

Да, если вы подклассифицируете RobolectricTestRunner, добавьте настраиваемый пакет в конструктор и загрузите свои классы Shadow в методе bindShadowClasses. Не нужно использовать андроид. * Трюк с пакетом.

(Примечание: это с robolectric-1.1)

В RobolectricTestRunner # setupApplicationState имеется несколько крючков, которые вы можете переопределить.

Вот моя реализация RobolectricTestRunner.

 import org.junit.runners.model.InitializationError; import com.android.testFramework.shadows.ShadowLoggerConfig; import com.xtremelabs.robolectric.Robolectric; import com.xtremelabs.robolectric.RobolectricTestRunner; public class RoboRunner extends RobolectricTestRunner { public RoboRunner(Class<?> clazz) throws InitializationError { super(clazz); addClassOrPackageToInstrument("package.you're.creating.shadows.of"); } @Override protected void bindShadowClasses() { super.bindShadowClasses(); // as you can see below, you really don't need this Robolectric.bindShadowClass(ShadowClass.class); } 

}

Дополнительные методы, которые вы можете подкласса (от RobolectricTestRunner.class)

 /** * Override this method to bind your own shadow classes */ protected void bindShadowClasses() { } /** * Override this method to reset the state of static members before each test. */ protected void resetStaticState() { } /** * Override this method if you want to provide your own implementation of Application. * <p/> * This method attempts to instantiate an application instance as specified by the AndroidManifest.xml. * * @return An instance of the Application class specified by the ApplicationManifest.xml or an instance of * Application if not specified. */ protected Application createApplication() { return new ApplicationResolver(robolectricConfig).resolveApplication(); } 

Вот где они вызваны в Robolectric TestRunner:

  public void setupApplicationState(final RobolectricConfig robolectricConfig) { setupLogging(); ResourceLoader resourceLoader = createResourceLoader(robolectricConfig); Robolectric.bindDefaultShadowClasses(); bindShadowClasses(); resourceLoader.setLayoutQualifierSearchPath(); Robolectric.resetStaticState(); resetStaticState(); DatabaseConfig.setDatabaseMap(this.databaseMap);//Set static DatabaseMap in DBConfig Robolectric.application = ShadowApplication.bind(createApplication(), resourceLoader); } 

В качестве обновления я смог создать тени своих собственных классов, пока я стараюсь привязать теневой класс до того, как какой-либо возможный загрузчик действует на этот класс. Итак, согласно инструкциям, в RoboRunner я сделал:

 @Override protected void bindShadowClasses() { Robolectric.bindShadowClass(ShadowLog.class); Robolectric.bindShadowClass(ShadowFlashPlayerFinder.class); } 

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

 package android.niftyco; public class FlashPlayerFinder { .. . 

И мой макет (тень) находится в моем тестовом пакете, как и следовало ожидать:

 package com.niftyco.android.test; @Implements(FlashPlayerFinder.class) public class ShadowFlashPlayerFinder { @RealObject private FlashPlayerFinder realFPF; public void __constructor(Context c) { //note the construction } @Implementation public boolean isFlashInstalled() { System.out.print("Let's pretend that Flash is installed\n"); return(true); } } 

Возможно, вам будет поздно, но отсюда: org.robolectric.bytecode.Setup, вы можете найти более подробную информацию о том, какие классы инструментальные.

  public boolean shouldInstrument(ClassInfo classInfo) { if (classInfo.isInterface() || classInfo.isAnnotation() || classInfo.hasAnnotation(DoNotInstrument.class)) { return false; } // allow explicit control with @Instrument, mostly for tests return classInfo.hasAnnotation(Instrument.class) || isFromAndroidSdk(classInfo); } public boolean isFromAndroidSdk(ClassInfo classInfo) { String className = classInfo.getName(); return className.startsWith("android.") || className.startsWith("libcore.") || className.startsWith("dalvik.") || className.startsWith("com.android.internal.") || className.startsWith("com.google.android.maps.") || className.startsWith("com.google.android.gms.") || className.startsWith("dalvik.system.") || className.startsWith("org.apache.http.impl.client.DefaultRequestDirector"); } .  public boolean shouldInstrument(ClassInfo classInfo) { if (classInfo.isInterface() || classInfo.isAnnotation() || classInfo.hasAnnotation(DoNotInstrument.class)) { return false; } // allow explicit control with @Instrument, mostly for tests return classInfo.hasAnnotation(Instrument.class) || isFromAndroidSdk(classInfo); } public boolean isFromAndroidSdk(ClassInfo classInfo) { String className = classInfo.getName(); return className.startsWith("android.") || className.startsWith("libcore.") || className.startsWith("dalvik.") || className.startsWith("com.android.internal.") || className.startsWith("com.google.android.maps.") || className.startsWith("com.google.android.gms.") || className.startsWith("dalvik.system.") || className.startsWith("org.apache.http.impl.client.DefaultRequestDirector"); }