アクティビティのカスタム シャドウを作成し、それを RobolectricTestRunner に登録した場合、フレームワークは、開始されるたびにカスタム シャドウでアクティビティをインターセプトしますか?
ありがとう。
アクティビティのカスタム シャドウを作成し、それを RobolectricTestRunner に登録した場合、フレームワークは、開始されるたびにカスタム シャドウでアクティビティをインターセプトしますか?
ありがとう。
短い答えはノーです。
Robolectric は、インターセプトして計測するクラスを選択します。この記事の執筆時点では、インスツルメントされる唯一のクラスは、これらのセレクターのいずれかに一致する完全修飾クラス名を持っている必要があります。
android.*
com.google.android.maps.*
org.apache.http.impl.client.DefaultRequestDirector
Robolectric が存在するすべての理由は、Android SDK jar で提供されるクラスが、JVM で (つまり、エミュレーターやデバイスではなく) 呼び出されたときに例外をスローすることです。アプリケーションのアクティビティには、「敵対的」ではないソースがあります (メソッドまたはコンストラクターが呼び出されたときに例外をスローしない可能性があります)。Robolectric の本来の目的は、アプリケーションのコードをテストできるようにすることです。これは、SDK の記述方法によっては不可能です。Robolectric が作成されたその他の理由には、次のようなものがあります。
コードを変更して、任意のクラスをシャドウすることができます。過去に、他のテストに敵対的な API を使用したテストの作成を支援するために、シャドウ機能をスタンドアロン ライブラリに抽出するという話がありました。
アクティビティをシャドウする理由は何ですか?
これは、Robolectric 2 で大幅に変更されました。独自の TestRunner を作成する代わりに、構成でカスタム シャドウを指定できます。
例えば:
@Config(shadows = {ShadowAudioManager.class, ShadowContextWrapper.class})
はい。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);
}
更新として、可能性のあるローダーがそのクラスで動作する前にシャドウ クラスをバインドするように注意している限り、独自のクラスのシャドウを作成することができました。したがって、指示に従って、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);
}
}