Ich habe gerade angefangen, mit Guice zu spielen, und ein Anwendungsfall, den ich mir vorstellen kann, ist, dass ich in einem Test nur eine einzelne Bindung überschreiben möchte. Ich denke, ich möchte den Rest der Bindungen auf Produktionsebene verwenden, um sicherzustellen, dass alles korrekt eingerichtet ist und um Doppelarbeit zu vermeiden.
Stellen Sie sich 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 InterfaceC überschreiben, während InterfaceA und InterfaceB im Takt bleiben, also möchte ich 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 folgendes versucht, ohne 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 will, oder belle ich den falschen Baum komplett an?
--- Follow-up: Es scheint, dass ich erreichen kann, was ich will, wenn ich das @ ImplementedBy-Tag auf der Schnittstelle verwende und dann einfach eine Bindung im Testfall bereitstelle, was gut funktioniert, wenn eine 1-1-Zuordnung zwischen besteht die Schnittstelle und Implementierung.
Nachdem wir dies mit einem Kollegen besprochen haben, scheinen wir den Weg zu beschreiten, ein ganzes Modul zu überschreiben und sicherzustellen, dass unsere Module korrekt definiert sind. Dies scheint jedoch ein Problem zu verursachen, wenn eine Bindung in einem Modul falsch platziert ist und verschoben werden muss, wodurch möglicherweise eine Reihe von Tests unterbrochen werden, da Bindungen möglicherweise nicht mehr zum Überschreiben verfügbar sind.
quelle
Antworten:
Dies ist möglicherweise nicht die Antwort, nach der Sie suchen, aber wenn Sie Komponententests schreiben, sollten Sie wahrscheinlich keinen Injektor verwenden und stattdessen Schein- oder Fälschungsobjekte von Hand injizieren.
Wenn Sie jedoch wirklich eine einzelne Bindung ersetzen möchten, können Sie Folgendes verwenden
Modules.override(..)
:Details finden Sie hier .
Aber wie der Javadoc für
Modules.overrides(..)
empfiehlt, sollten Sie Ihre Module so gestalten, dass Sie keine Bindungen überschreiben müssen. In dem von Ihnen angegebenen Beispiel können Sie dies erreichen, indem Sie die Bindung vonInterfaceC
in ein separates Modul verschieben.quelle
ovveride
verliert ich dabei das RichtigeStage
(dh ENTWICKLUNG wird systematisch verwendet).Warum nicht die Vererbung verwenden? Sie können Ihre spezifischen Bindungen in der
overrideMe
Methode überschreiben und gemeinsam genutzte Implementierungen in derconfigure
Methode belassen.Und schließlich erstellen Sie Ihren Injektor folgendermaßen:
quelle
@Override
scheint nicht zu funktionieren. Vor allem, wenn es mit einer Methode gemacht wird, dass@Provides
etwas.Wenn Sie Ihr Produktionsmodul nicht ändern möchten und wenn Sie eine Standard-Maven-ähnliche Projektstruktur wie haben
Sie können einfach eine neue Klasse
ConcreteC
in Ihrem Testverzeichnis erstellen, indem Sie dasselbe Paket wie für Ihre ursprüngliche Klasse verwenden. Guice wird dann binden ,InterfaceC
umConcreteC
von Ihrem Testverzeichnis , während alle anderen Schnittstellen an Ihre Produktion Klassen gebunden.quelle
Sie möchten Juckito verwenden, wo Sie Ihre benutzerdefinierte Konfiguration für jede Testklasse deklarieren können.
quelle
In einem anderen Setup haben wir mehr als eine Aktivität in separaten Modulen definiert. Die Aktivität, in die eingefügt wird, befindet sich in einem Android-Bibliotheksmodul mit einer eigenen RoboGuice-Moduldefinition in der Datei AndroidManifest.xml.
Das Setup sieht so aus. Im Bibliotheksmodul gibt es folgende Definitionen:
AndroidManifest.xml:
Dann wird ein Typ injiziert:
Einige Standardimplementierungen von Foo:
MainModule konfiguriert die FooThing-Implementierung für Foo:
Und schließlich eine Aktivität, die Foo verbraucht:
Im konsumierenden Android-Anwendungsmodul möchten wir verwenden,
SomeActivity
aber zu Testzwecken unser eigenes injizierenFoo
.Man könnte argumentieren, die Modulbehandlung für die Clientanwendung verfügbar zu machen. Wir müssen jedoch die injizierten Komponenten größtenteils ausblenden, da das Bibliotheksmodul ein SDK ist und das Anzeigen von Teilen größere Auswirkungen hat.
(Denken Sie daran, dies dient zum Testen, damit wir die Interna von SomeActivity kennen und wissen, dass es ein (Paket sichtbar) Foo verbraucht.)
Die Art und Weise, wie ich fand, dass das funktioniert, macht Sinn; Verwenden Sie zum Testen die vorgeschlagene Überschreibung :
Wenn
SomeActivity
es jetzt gestartet wird, wird esOtherFooThing
für seine injizierteFoo
Instanz abgerufen .Es ist eine sehr spezielle Situation, in der in unserem Fall OtherFooThing intern zum Aufzeichnen von Testsituationen verwendet wurde, während FooThing standardmäßig für alle anderen Zwecke verwendet wurde.
Denken Sie daran, wir sind mit
#newDefaultRoboModule
unseren Unit - Tests, und es funktioniert einwandfrei.quelle