Właśnie zacząłem grać z Guice i przypadkiem użycia, który przychodzi mi do głowy, jest to, że w teście chcę zastąpić pojedyncze wiązanie. Myślę, że chciałbym użyć pozostałych powiązań na poziomie produkcyjnym, aby upewnić się, że wszystko jest poprawnie skonfigurowane i uniknąć duplikacji.
Więc wyobraź sobie, że mam następujący moduł
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);
}
}
W moim teście chcę tylko przesłonić InterfaceC, zachowując jednocześnie InterfaceA i InterfaceB, więc chciałbym coś takiego:
Module testModule = new Module() {
public void configure(Binder binder) {
binder.bind(InterfaceC.class).to(MockC.class);
}
};
Guice.createInjector(new ProductionModule(), testModule);
Próbowałem również następujących rzeczy, bez powodzenia:
Module testModule = new ProductionModule() {
public void configure(Binder binder) {
super.configure(binder);
binder.bind(InterfaceC.class).to(MockC.class);
}
};
Guice.createInjector(testModule);
Czy ktoś wie, czy można robić to, co chcę, czy też całkowicie szczekam na niewłaściwe drzewo?
--- Kontynuacja: wydaje się, że mogę osiągnąć to, co chcę, jeśli użyję tagu @ImplementedBy w interfejsie, a następnie po prostu dostarczę powiązanie w przypadku testowym, co działa dobrze, gdy istnieje mapowanie 1-1 między interfejs i implementacja.
Ponadto po omówieniu tego ze współpracownikiem wydaje się, że wybralibyśmy drogę zastąpienia całego modułu i upewnienia się, że nasze moduły zostały poprawnie zdefiniowane. Wydaje się, że może to jednak powodować problem, gdy powiązanie jest niewłaściwie umieszczone w module i musi zostać przeniesione, co może spowodować zerwanie obciążenia testów, ponieważ powiązania mogą nie być już dostępne do zastąpienia.
źródło
Odpowiedzi:
To może nie być odpowiedź, której szukasz, ale jeśli piszesz testy jednostkowe, prawdopodobnie nie powinieneś używać wtryskiwacza, a raczej ręcznie wstrzykiwać fałszywe obiekty.
Z drugiej strony, jeśli naprawdę chcesz zastąpić pojedyncze wiązanie, możesz użyć
Modules.override(..)
:Zobacz szczegóły tutaj .
Ale jak
Modules.overrides(..)
zaleca javadoc for , powinieneś zaprojektować swoje moduły w taki sposób, aby nie trzeba było nadpisywać powiązań. W podanym przykładzie można to osiągnąć, przenosząc powiązanie programuInterfaceC
do osobnego modułu.źródło
ovveride
gubi to, co właściweStage
(czyli systematycznie używa się ROZWOJU).Dlaczego nie skorzystać z dziedziczenia? Możesz zastąpić określone powiązania w
overrideMe
metodzie, pozostawiając udostępnione implementacje wconfigure
metodzie.I na koniec stwórz swój wtryskiwacz w ten sposób:
źródło
@Override
że nie działa. Zwłaszcza jeśli jest to zrobione metodą, że@Provides
coś.Jeśli nie chcesz zmieniać modułu produkcyjnego i masz domyślną strukturę projektu podobną do Mavena, taką jak
Możesz po prostu utworzyć nową klasę
ConcreteC
w katalogu testowym, używając tego samego pakietu, co w przypadku oryginalnej klasy. Guice następnie połączyInterfaceC
sięConcreteC
z twoim katalogiem testowym, podczas gdy wszystkie inne interfejsy zostaną powiązane z twoimi klasami produkcyjnymi.źródło
Chcesz użyć Juckito, w którym możesz zadeklarować własną konfigurację dla każdej klasy testowej.
źródło
W innej konfiguracji mamy więcej niż jedną aktywność zdefiniowaną w oddzielnych modułach. Działanie, które jest wstrzykiwane, znajduje się w module biblioteki systemu Android, z własną definicją modułu RoboGuice w pliku AndroidManifest.xml.
Konfiguracja wygląda następująco. W module bibliotecznym znajdują się następujące definicje:
AndroidManifest.xml:
Następnie mamy wstrzyknięty typ:
Niektóre domyślne implementacje Foo:
MainModule konfiguruje implementację FooThing dla Foo:
I wreszcie działanie, które zużywa Foo:
W konsumującym module aplikacji na Androida chcielibyśmy użyć,
SomeActivity
ale do celów testowych wstrzyknąć własneFoo
.Można by argumentować, aby ujawnić obsługę modułu aplikacji klienckiej, jednak musimy głównie ukryć wstrzykiwane składniki, ponieważ moduł biblioteki jest zestawem SDK, a ujawnianie elementów ma większe konsekwencje.
(Pamiętaj, to jest do testowania, więc znamy wewnętrzne cechy SomeActivity i wiemy, że zużywa (widoczny pakiet) Foo).
Sposób, w jaki to działa, ma sens; użyj sugerowanego zastąpienia do testowania :
Teraz, po
SomeActivity
uruchomieniu, otrzymaOtherFooThing
dla swojej wstrzykniętejFoo
instancji.Jest to bardzo specyficzna sytuacja, w której w naszym przypadku OtherFooThing był używany wewnętrznie do rejestrowania sytuacji testowych, podczas gdy FooThing był używany domyślnie do wszystkich innych zastosowań.
Należy pamiętać, że są za pomocą
#newDefaultRoboModule
naszych testów jednostkowych i działa bez zarzutu.źródło