如果我为我的Activity编写一个自定义Shadow,并使用RobolectricTestRunner注册它,那么框架是否会在我的自定义Shadow启动时拦截Activity?
感谢。
答案 0 :(得分:11)
简短的回答是否定的。
Robolectric选择拦截哪些类别和乐器。在撰写本文时,将要检测的唯一类必须具有与这些选择器之一匹配的完全限定类名:
android.*
com.google.android.maps.*
org.apache.http.impl.client.DefaultRequestDirector
Robolectric存在的全部原因是Android SDK jar中提供的类在JVM(即不在模拟器或设备上)中调用时会抛出异常。您的应用程序的Activity具有非“敌对”的源(在调用方法或构造函数时,它可能不会抛出异常)。 Robolectric的目的是允许您对应用程序的代码进行测试,否则由于SDK的编写方式而无法实现。创建Robolectric的其他一些原因是:
代码可以清楚地更改为遮蔽任何类。过去一直在讨论将阴影特征提取到一个独立的库中,以帮助使用其他一些测试恶意api编写测试。
为什么要隐藏您的活动?
答案 1 :(得分:9)
使用Robolectric 2时,这已经发生了很大变化。您可以指定custom shadows in the configuration而不是编写自己的TestRunner。
例如:
@Config(shadows = {ShadowAudioManager.class, ShadowContextWrapper.class})
答案 2 :(得分:3)
是的,如果您继承了RobolectricTestRunner,请将自定义包添加到构造函数中,并在bindShadowClasses方法中加载Shadow类。不需要使用android。*包技巧。
(注意:这是使用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);
}
答案 3 :(得分:2)
作为更新,我已经能够创建自己的类的阴影,只要在任何可能的加载器作用于该类之前小心绑定阴影类。所以,按照说明,我在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);
}
}
答案 4 :(得分:2)
可能会迟到,但是从这里开始: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");
}