Ich versuche, einen Unit-Test für eine einfache Bean zu schreiben, die in meinem Programm zum Validieren von Formularen verwendet wird. Die Bean ist mit Anmerkungen versehen @Component
und verfügt über eine Klassenvariable, die mit initialisiert wird
@Value("${this.property.value}") private String thisProperty;
Ich möchte Unit-Tests für die Validierungsmethoden in dieser Klasse schreiben, möchte dies jedoch nach Möglichkeit ohne Verwendung der Eigenschaftendatei tun. Meine Argumentation dahinter ist, dass wenn sich der Wert, den ich aus der Eigenschaftendatei ziehe, ändert, ich möchte, dass dies meinen Testfall nicht beeinflusst. Mein Testfall testet den Code, der den Wert validiert, nicht den Wert selbst.
Gibt es eine Möglichkeit, Java-Code in meiner Testklasse zu verwenden, um eine Java-Klasse zu initialisieren und die Spring @ Value-Eigenschaft in dieser Klasse zu füllen, um sie dann zum Testen zu verwenden?
Ich habe dieses How To gefunden , das nah zu sein scheint, aber immer noch eine Eigenschaftendatei verwendet. Ich würde lieber alles Java-Code sein.
Antworten:
Wenn möglich, würde ich versuchen, diesen Test ohne Spring Context zu schreiben. Wenn Sie diese Klasse in Ihrem Test ohne Feder erstellen, haben Sie die volle Kontrolle über ihre Felder.
Um das
@value
Feld festzulegen, können Sie Federn verwenden.ReflectionTestUtils
Es gibt eine MethodesetField
zum Festlegen privater Felder.@see JavaDoc: ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)
quelle
org.springframework.test.util.ReflectionTestUtils.setField(classUnderTest, "field", "value");
@Value
Anmerkung in den Konstruktorparameter verschieben. Dies macht den Testcode viel einfacher, wenn der Code manuell geschrieben wird, und Spring Boot ist das egal.Seit Spring 4.1 können Sie Eigenschaftswerte nur im Code mithilfe von
org.springframework.test.context.TestPropertySource
Anmerkungen auf Klassenebene für Komponententests einrichten . Sie können diesen Ansatz auch zum Einfügen von Eigenschaften in abhängige Bean-Instanzen verwendenBeispielsweise
Hinweis: Es ist erforderlich, eine Instanz
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
im Spring-Kontext zu habenBearbeiten 24-08-2017: Wenn Sie SpringBoot 1.4.0 und höher verwenden, können Sie Tests mit
@SpringBootTest
und@SpringBootConfiguration
Anmerkungen initialisieren . Mehr Infos hierIm Falle von SpringBoot haben wir folgenden Code
quelle
Missbrauche keine privaten Felder, die durch Reflexion erhalten / gesetzt werden
Die Verwendung von Reflexion, wie sie in mehreren Antworten hier erfolgt, ist etwas, das wir vermeiden könnten.
Es bringt hier einen kleinen Wert, während es mehrere Nachteile aufweist:
@Value String field
. Morgen können Sie5
oder10
von ihnen in dieser Klasse deklarieren , und Sie sind sich möglicherweise nicht einmal bewusst, dass Sie das Design der Klasse verringern. Mit einem besser sichtbaren Ansatz zum Festlegen dieser Felder (z. B. Konstruktor) werden Sie zweimal überlegen, bevor Sie alle diese Felder hinzufügen, und Sie werden sie wahrscheinlich in eine andere Klasse einkapseln und verwenden@ConfigurationProperties
.Machen Sie Ihre Klasse sowohl einheitlich als auch in Integration testbar
Um sowohl einfache Komponententests (dh ohne laufenden Federbehälter) als auch Integrationstests für Ihre Spring-Komponentenklasse schreiben zu können, müssen Sie diese Klasse mit oder ohne Spring verwendbar machen.
Das Ausführen eines Containers in einem Komponententest, wenn dies nicht erforderlich ist, ist eine schlechte Vorgehensweise, die lokale Builds verlangsamt: Das möchten Sie nicht.
Ich habe diese Antwort hinzugefügt, da keine Antwort hier diese Unterscheidung zu zeigen scheint und sie sich daher systematisch auf einen laufenden Container stützen.
Daher denke ich, dass Sie diese Eigenschaft verschieben sollten, die als intern innerhalb der Klasse definiert ist:
in einen Konstruktorparameter, der von Spring eingefügt wird:
Unit Test Beispiel
Sie können instanziieren
Foo
ohne Spring undproperty
dank des Konstruktors einen beliebigen Wert einfügen:Integrationstestbeispiel
Sie können die Eigenschaft auf diese einfache Weise im Kontext von Spring Boot einfügen, dank der
properties
Attributs@SpringBootTest
:Sie könnten als Alternative verwenden
@TestPropertySource
, es wird jedoch eine zusätzliche Anmerkung hinzugefügt:Mit Spring (ohne Spring Boot) sollte es etwas komplizierter sein, aber da ich Spring ohne Spring Boot schon lange nicht mehr verwendet habe, möchte ich nicht lieber etwas Dummes sagen.
Als Randnotiz: Wenn Sie viele
@Value
Felder festlegen müssen, ist das Extrahieren in eine mit Anmerkungen versehene Klasse@ConfigurationProperties
relevanter, da wir keinen Konstruktor mit zu vielen Argumenten möchten.quelle
final
, dhprivate String final property
Wenn Sie möchten, können Sie Ihre Tests weiterhin in Spring Context ausführen und die erforderlichen Eigenschaften in der Spring-Konfigurationsklasse festlegen. Wenn Sie JUnit verwenden, verwenden Sie SpringJUnit4ClassRunner und definieren Sie eine dedizierte Konfigurationsklasse für Ihre Tests wie folgt:
Die zu testende Klasse:
Die Testklasse:
Und die Konfigurationsklasse für diesen Test:
Trotzdem würde ich diesen Ansatz nicht empfehlen, ich habe ihn hier nur als Referenz hinzugefügt. Meiner Meinung nach ist es viel besser, Mockito Runner zu verwenden. In diesem Fall führen Sie in Spring überhaupt keine Tests durch, was viel klarer und einfacher ist.
quelle
Dies scheint zu funktionieren, obwohl es immer noch etwas ausführlich ist (ich hätte gerne noch etwas kürzeres):
quelle
@TestProperty
Anmerkung hinzufügen können .@Value
s bevölkert , unabhängig davon, ob die entsprechende Eigenschaft festgelegt ist oder nicht.Das Hinzufügen von PropertyPlaceholderConfigurer zur Konfiguration funktioniert für mich.
Und in der Testklasse
quelle