Frage

Ich habe gerade angefangen, mit Guice, und ein use-case, den ich denken kann, ist, dass in einem test, ich möchte nur zum überschreiben eines einzelnen Bindung.Ich glaube, ich würde wie zu verwenden die rest der Ebene der Produktion Bindungen, um sicherzustellen, dass alles richtig konfiguriert ist und überschneidungen zu vermeiden.

Stellen Sie sich also vor, ich habe das folgende Modul

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);
    }
}

Und in meinem test möchte ich nur zu überschreiben, InterfaceC, während InterfaceA und InterfaceB-Schnittstelle intakt, so möchte ich so etwas wie:

Module testModule = new Module() {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(new ProductionModule(), testModule);

Ich habe auch versucht, die folgenden, mit der kein Glück:

Module testModule = new ProductionModule() {
    public void configure(Binder binder) {
        super.configure(binder);
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(testModule);

Weiß jemand, ob es möglich ist, das zu tun, was ich möchte, oder bin ich komplett auf dem Holzweg??

--- Follow-up:Es scheint, ich kann erreichen, was ich will, wenn ich die @ImplementedBy-tag auf der Schnittstelle und dann nur eine Bindung in der test-Fall, die funktioniert gut, wenn es eine 1-1-Zuordnung zwischen der Schnittstelle und Implementierung.

Auch, nach Rücksprache mit einem Kollegen, scheint es, wir würden den Kopf die Straße hinunter zu überschreiben eines Moduls und sicherstellen, wir haben unsere Module korrekt definiert.Dies scheint, wie es könnte ein problem obwohl, wo ein verbindliches verlegt, die in ein Modul und muss bewegt werden, damit eventuell bricht eine Last von tests als Bindungen möglicherweise nicht mehr verfügbar sein, werden überschrieben.

War es hilfreich?

Lösung

Dies ist möglicherweise nicht die Antwort, die Sie suchen, aber wenn Sie schreiben unit-tests, sollten Sie wahrscheinlich nicht mit einem Injektor und eher injizieren verspotten oder gefälschte Objekte von hand.

Auf der anderen Seite, wenn Sie wirklich wollen zu ersetzen eine einzige Bindung, die Sie verwenden könnten 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()));

Siehe details hier.

Aber wie in der javadoc für Modules.overrides(..) empfiehlt, sollten Sie design Ihre Module in einer Weise, dass Sie brauchen nicht zu überschreiben Bindungen.In dem Beispiel, das Sie gab, Sie konnte erreichen, dass durch das verschieben der Bindung von InterfaceC um ein separates Modul.

Andere Tipps

Warum nicht die Vererbung verwenden?Sie knnen Ihre spezifischen Bindungen in overrideMe Methode verlassen geteilten Implementierungen in configure Methode.

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);
    }
}

Und schließlich erstellen Sie Ihre Injektor-auf diese Weise:

Guice.createInjector(new TestModule());

Wenn Sie nicht wollen, ändern Sie Ihre Produktion Modul und wenn Sie eine Standard-maven-wie Projekt-Struktur wie

src/test/java/...
src/main/java/...

Sie können nur eine neue Klasse erstellen ConcreteC in Ihrem Verzeichnis test mit dem gleichen Paket wie für Ihre ursprüngliche Klasse.Guice wird dann binden InterfaceC zu ConcreteC aus dem test-Verzeichnis in der Erwägung, dass alle anderen Schnittstellen gebunden werden, um Ihre Produktion-Klassen.

Sie verwenden möchten Juckito wo können Sie erklären, Ihre benutzerdefinierte Konfiguration für jede test-Klasse.

@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();
    }
}

In einem anderen setup, wir haben mehr als eine Aktivität definiert, die in separate Module.Die Tätigkeit, die eingespritzt wird, ist als Android-Bibliothek-Modul, mit seinen eigenen RoboGuice-Modul-definition in der AndroidManifest.xml Datei.

Das setup sieht wie folgt aus.In der Bibliothek gibt es diese Definitionen:

AndroidManifest.xml:

<application android:allowBackup="true">
    <activity android:name="com.example.SomeActivity/>
    <meta-data
        android:name="roboguice.modules"
        android:value="com.example.MainModule" />
</application>

Dann haben wir einen Typ injiziert werden:

interface Foo { }

Einige Standard-Implementierung von Foo:

class FooThing implements Foo { }

MainModule konfiguriert die FooThing Umsetzung für Foo:

public class MainModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Foo.class).to(FooThing.class);
    }
}

Und schließlich, eine Aktivität, die verbraucht Foo:

public class SomeActivity extends RoboActivity {
    @Inject
    private Foo foo;
}

In der Konsum-Android-Anwendung-Modul, wir würden wie zu verwenden SomeActivity aber für Testzwecke, unsere eigenen Spritzen Foo.

public class SomeOtherActivity extends Activity {
    @Override
    protected void onResume() {
        super.onResume();

        Intent intent = new Intent(this, SomeActivity.class);
        startActivity(intent);
    }
}

Man könnte argumentieren, setzen Sie das Modul Umgang mit der client-Anwendung, jedoch müssen wir meist verstecken sich die Komponenten injiziert werden, da die Bibliothek-Modul ist ein SDK, und das Verfügbarmachen Stücke hat größere Auswirkungen.

(Denken Sie daran, dies ist für das testen, damit wir wissen, von Interna SomeActivity, und wissen es verbraucht (Paket sichtbar) Foo).

Die Art, wie ich gefunden, die funktioniert, macht Sinn;verwenden Sie die vorgeschlagenen überschreiben Prüfung:

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);
    }
}

Nun, wenn SomeActivity gestartet, es wird OtherFooThing für seine gespritzt Foo Instanz.

Es ist eine sehr spezifische situation, in der, in unserem Fall, OtherFooThing wurde intern verwendet, um Rekord-test-Situationen, während FooThing verwendet wurde, standardmäßig für alle anderen Verwendungen.

Halten in Geist, wir sind Verwendung #newDefaultRoboModule in unseren unit-tests, und es funktioniert einwandfrei.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top