Guiceの中でバインディングのオーバーライド
-
20-08-2019 - |
質問
私はGuiceので遊んで始めた、と私は考えることができるのユースケースは、テストには、私はちょうど単一の結合を上書きするということです。私は、私はすべてが正しくセットアップであることを確認して、重複を避けるために、生産レベルのバインディングの残りの部分を使用したいと考えています。
だから私は、次のモジュールを持っている想像
public class ProductionModule implements Module {
public void configure(Binder binder) {
binder.bind(InterfaceA.class).to(ConcreteA.class);
binder.bind(InterfaceB.class).to(ConcreteB.class);
binder.bind(InterfaceC.class).to(ConcreteC.class);
}
}
そして、私のテストでは、私が唯一のタクトでInterfaceAとInterfaceBを維持しながら、InterfaceCを上書きしたいので、私のような何かをしたいと思います:
Module testModule = new Module() {
public void configure(Binder binder) {
binder.bind(InterfaceC.class).to(MockC.class);
}
};
Guice.createInjector(new ProductionModule(), testModule);
また、私は運と、以下のことを試してみました
Module testModule = new ProductionModule() {
public void configure(Binder binder) {
super.configure(binder);
binder.bind(InterfaceC.class).to(MockC.class);
}
};
Guice.createInjector(testModule);
それは私がやりたいことは可能ですか、私は完全に間違ってツリーを吠えていた場合、誰もが知ってい??
---フォローアップ: 私がインターフェイス上@ImplementedByタグを利用して、その後、ちょうどインタフェースと実装の間で1-1のマッピングがある場合にはうまく動作テストケースで結合を提供する場合、私は私が欲しいものを達成できると思われます。
また、同僚とこれを議論した後、我々がモジュール全体をオーバーライドし、私たちは私たちのモジュールが正しく定義されている確保の道を頭だろうと思われます。バインディングがモジュールに置き忘れとバインディングはもはや上書きするために利用可能でないかもしれないとして、これおそらくテストの負荷を壊し、移動する必要があるところけれども、それは問題を引き起こす可能性がありますように。これは思えるます。
解決
これはあなたが探している答えではないかもしれませんが、あなたはユニットテストを書いている場合、あなたはおそらく注射器を使用してすべきではないと、むしろ手でモックまたは偽のオブジェクトを注入することがます。
あなたが本当に単一の結合を置換する場合一方、あなたが使用することができますModules.override(..)
:
public class ProductionModule implements Module {
public void configure(Binder binder) {
binder.bind(InterfaceA.class).to(ConcreteA.class);
binder.bind(InterfaceB.class).to(ConcreteB.class);
binder.bind(InterfaceC.class).to(ConcreteC.class);
}
}
public class TestModule implements Module {
public void configure(Binder binder) {
binder.bind(InterfaceC.class).to(MockC.class);
}
}
Guice.createInjector(Modules.override(new ProductionModule()).with(new TestModule()));
詳細<のhref = "HTTPを参照してください://google-guice.googlecode.com/git/javadoc/com/google/inject/util/Modules.html#override%28com.google.inject.Moduleを... %29" のrel = "noreferrer">ここを。
しかし、推奨していますModules.overrides(..)
のjavadocとして、あなたはバインディングをオーバーライドする必要はありません、このような方法であなたのモジュールを設計する必要があります。あなたが与えた例では、別のモジュールにInterfaceC
の結合を移動していることを達成することができます。
他のヒント
なぜ継承を使用するには?あなたがでoverrideMe
方法共有の実装を残し、configure
方法であなたの特定のバインディングを上書きすることができます。
public class DevModule implements Module {
public void configure(Binder binder) {
binder.bind(InterfaceA.class).to(TestDevImplA.class);
overrideMe(binder);
}
protected void overrideMe(Binder binder){
binder.bind(InterfaceC.class).to(ConcreteC.class);
}
};
public class TestModule extends DevModule {
@Override
public void overrideMe(Binder binder) {
binder.bind(InterfaceC.class).to(MockC.class);
}
}
そして最後に、あなたのインジェクタをこのように作成します:
Guice.createInjector(new TestModule());
あなたは、生産モジュールを変更したくない場合は、
のように、デフォルトの達人のようなプロジェクト構造を持っている場合src/test/java/...
src/main/java/...
あなたは自分の元のクラスと同じパッケージを使用してテストディレクトリにConcreteC
新しいクラスを作成することができます。 Guiceのは、他のすべてのインターフェイスは、本番クラスにバインドされるのに対し、テストディレクトリからInterfaceC
する<=>バインドします。
あなたが使用したい Juckito のどこに各テストクラス用のカスタム設定を宣言することができます。
@RunWith(JukitoRunner.class)
class LogicTest {
public static class Module extends JukitoModule {
@Override
protected void configureTest() {
bind(InterfaceC.class).to(MockC.class);
}
}
@Inject
private InterfaceC logic;
@Test
public testLogicUsingMock() {
logic.foo();
}
}
異なるセットアップでは、我々は、複数の活動は別のモジュールで定義されています。注入されるの活動は、AndroidManifest.xmlファイル内に独自のRoboGuiceモジュールの定義で、Androidのライブラリモジュールです。
セットアップは、次のようになります。ライブラリモジュールで、これらの定義があります:
のAndroidManifest.xmlます:
<application android:allowBackup="true">
<activity android:name="com.example.SomeActivity/>
<meta-data
android:name="roboguice.modules"
android:value="com.example.MainModule" />
</application>
その後、我々はタイプが注入されています:
interface Foo { }
はFooのいくつかのデフォルトの実装ます:
class FooThing implements Foo { }
MainModuleはFooのためのFooThingの実装を設定します:
public class MainModule extends AbstractModule {
@Override
protected void configure() {
bind(Foo.class).to(FooThing.class);
}
}
そして最後に、Fooの消費活動:
public class SomeActivity extends RoboActivity {
@Inject
private Foo foo;
}
がかかりAndroidのアプリケーションモジュールでは、我々は注入し、テスト目的のために、使用したいSomeActivity
だろうが、私たち自身のFoo
。
public class SomeOtherActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
Intent intent = new Intent(this, SomeActivity.class);
startActivity(intent);
}
}
一つは、クライアントアプリケーションに処理モジュールを公開するために主張するかもしれない、しかし、我々は、主にライブラリモジュールがSDKで、作品をさらすことは大きな意味を持っているので、注入されるコンポーネントを非表示にする必要があります。
(これはテスト用ですので、我々はSomeActivityの内部を知って、それが(パッケージ見える)はFooを消費知って、覚えておいてください)。
私は働くことが判明方法は理にかなっています。
テストのために示唆オーバーライドを使用public class SomeOtherActivity extends Activity {
private class OverrideModule
extends AbstractModule {
@Override
protected void configure() {
bind(Foo.class).to(OtherFooThing.class);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RoboGuice.overrideApplicationInjector(
getApplication(),
RoboGuice.newDefaultRoboModule(getApplication()),
Modules
.override(new MainModule())
.with(new OverrideModule()));
}
@Override
protected void onResume() {
super.onResume();
Intent intent = new Intent(this, SomeActivity.class);
startActivity(intent);
}
}
OtherFooThing
が開始されたときにさて、それはその注入さ#newDefaultRoboModule
例えば<=>取得します。
これは、我々の場合には、OtherFooThingは、テストの状況を記録するために内部的に使用された非常に特殊な状況は、です。
の私たちのユニットテストで<=>使用して、それが完璧に動作している私たちはを、覚えておいてください。