2010-03-15 14 views
27

Ich gab Google Guice die Verantwortung für die Verkabelung meiner Objekte. Aber, wie kann ich prüfen, ob die Bindungen gut funktionieren. Beispiel: Angenommen, wir haben eine Klasse A, die eine Abhängigkeit B hat. Wie kann ich testen, ob B richtig injiziert wurde?Wie Test Guice Injektionen?

class A { 
    private B b; 
    public A() {} 

    @Inject 
    public void setB(B b) { 
     this.b = b 
    } 
} 

Hinweis A hat keine getB() Methode, und ich möchte behaupten, dass A.b nicht null.

Antwort

40

Für jedes komplexe Guice-Projekt sollten Sie Tests hinzufügen, um sicherzustellen, dass die Module zum Erstellen Ihrer Klassen verwendet werden können. Wenn in Ihrem Beispiel B ein Typ wäre, für den Guice nicht herausfinden konnte, wie er erstellt werden soll, dann wird Guice nicht in der Lage sein, A zu erstellen. Wenn A nicht benötigt wurde, um den Server zu starten, wurde er benötigt Anfrage, das würde Probleme verursachen.

In meinen Projekten schreibe ich Tests für nicht-triviale Module. Für jedes Modul verwende ich requireBinding(), um zu deklarieren, welche Bindungen das Modul benötigt, aber nicht definiert. In meinen Tests erstelle ich einen Guice-Injektor mit dem zu testenden Modul und einem weiteren Modul, das die erforderlichen Bindungen bereitstellt. Hier ist ein Beispiel mit JUnit4 und JMock:

Beachten Sie, wie der Test nur nach einem Anbieter fragt. Das ist ausreichend, um zu bestimmen, dass Guice die Bindungen lösen konnte. Wenn LoginService von einer Provider-Methode erstellt wurde, würde dieser Test den Code in der Provider-Methode nicht testen.

Dieser Test testet auch nicht, dass Sie das richtige Ding an UserDao gebunden haben, oder dass UserDao korrekt angegeben wurde. Manche würden argumentieren, dass diese Art von Dingen selten eine Überprüfung wert ist; Wenn es ein Problem gibt, passiert es einmal. Sie sollten "testen, bis die Angst zur Langeweile wird".

Ich finde Modultests nützlich, weil ich oft neue Injektionspunkte hinzufüge und es leicht vergißt, eine Bindung hinzuzufügen.

Die Anrufe requireBinding() können Guice helfen, fehlende Bindungen zu finden, bevor es Ihren Injektor zurückbringt! Im obigen Beispiel würde der Test immer noch funktionieren, wenn die requireBinding() Anrufe nicht da wären, aber ich mag sie, weil sie als Dokumentation dienen.

Für kompliziertere Module (wie meine Root-Modul) Ich könnte Modules.override() verwenden Bindungen außer Kraft zu setzen, die ich bei Testzeit nicht (zum Beispiel will, wenn ich, dass mein Root-Objekt zu überprüfen, erstellt werden soll, mich wahrscheinlich don möchte nicht, dass ein Objekt erstellt wird, das eine Verbindung zur Datenbank herstellt. Bei einfachen Projekten können Sie nur das oberste Modul testen.

Beachten Sie, dass Guice will not inject nulls, außer das Feld wie mit @Nullable kommentiert, so dass Sie sehr selten überprüfen müssen, dass die injizierten Objekte in Ihren Tests nicht null sind.In der Tat, wenn ich Konstruktoren mit @Inject kommentieren ich nicht die Mühe zu überprüfen, ob die Parameter sind null (in der Tat, meine Tests oft injizieren null in den Konstruktor, um die Tests einfach zu halten).

+0

Vielen Dank. Ihre Argumente sind sehr klar. Ich habe Abhängigkeiten, die nicht erstellt werden, nachdem Anwendung bereitgestellt wurde – yeraycaballero

+1

'meine Tests injizieren oft Null in den Konstruktor, um die Tests einfach zu halten' => das kann ein Hinweis darauf sein, dass Ihre Klasse nicht so zusammenhängend sein kann – beluchin

+0

@beluchin könnten Sie erklären Was meinst du? Ich versuche zu vermeiden, "echte Arbeit" in meinem Konstruktor zu machen, also ist das Eingeben eines "Null" in den Konstruktor selten ein Problem. Wenn ich eine Klasse teste und die Methode (n), die ich teste, keins der Felder verwendet, übergebe eine Null für diesen Konstruktorparameter die einfachste Aufgabe. Wenn das nicht funktioniert, injiziere ich ein Mock-Objekt (für Services) oder eine echte Instanz (für Value-Objekte), aber beides macht den Code komplizierter als es wäre, wenn ich nur 'null' – NamshubWriter

-1

Ich denke nicht, dass Sie testen sollten private Mitglieder gesetzt werden. Besser gegen die öffentliche Schnittstelle Ihrer Klasse testen. Wenn Element "b" nicht injiziert wird, erhalten Sie wahrscheinlich eine NullPointerException, die Ihre Tests ausführt, was eine Menge Warnungen sein sollte.

1

IMHO, Sie sollten das nicht testen. Die Jungs von Google Guice haben die Unit-Tests, um zu bestätigen, dass die Injektionen wie erwartet funktionieren - schließlich ist Guice dafür konzipiert. Sie sollten nur Tests für Ihren eigenen Code schreiben (A und B).

+2

Ich denke, Sie müssen DI ein wenig mehr verstehen. Der Punkt ist, dass das DI-Framework zu aufgebauten Instanzen führt und diese für Sie injizieren wird, wo es angebracht ist (deshalb wurden sie erstellt) - Sie werden Ihre Erstellungs- und Geschäftslogik trennen. Jetzt können Sie sie separat testen. Das Testen Ihres Erstellungscodes bedeutet jedoch nicht, dass Sie sicherstellen, dass Guice wie vorgesehen funktioniert. Wenn Sie der Bibliothek nicht vertrauen, sollten Sie vielleicht etwas anderes verwenden. – gpampara

+12

Die Guice Jungs sind nicht mit Ihrer Aussage einverstanden. Zitat: "Wenn Ihre Anbieter komplex sind, sollten Sie sie testen!" (http://code.google.com/p/google-guice/wiki/ProviderBindings) – Joe23

+4

@ Joe23 - Guice-Anbieter testen und Guice-Bindungen testen sind zwei verschiedene Dinge. – topchef

3

Eine andere Möglichkeit, Ihre Konfiguration zu testen, besteht darin, eine Test-Suite zu verwenden, die Ihre App Ende-zu-Ende testet. Obwohl End-to-End-Tests Anwendungsfälle nominell testen, prüfen sie indirekt, ob Ihre App korrekt konfiguriert ist (alle Abhängigkeiten sind verdrahtet usw.). Unit-Tests sollten sich dagegen ausschließlich auf die Domäne und nicht auf den Kontext konzentrieren, in dem Ihr Code bereitgestellt wird.

Ich stimme auch mit NamshubWriter's Antwort. Ich bin nicht gegen Tests, die Konfiguration überprüfen, solange sie in einer separaten Testsuite zu Ihren Komponententests gruppiert sind.