Verwenden von SpringJUnit4ClassRunner mit Parameterized

1. Übersicht

In diesem Tutorial erfahren Sie, wie Sie einen in JUnit4 implementierten Spring-Integrationstest mit einem parametrisierten JUnit-Testläufer parametrisieren .

2. SpringJUnit4ClassRunner

SpringJUnit4ClassRunner ist eine Implementierung von JUnit4 des ClassRunner , die Spring bettet TestContextManager in einen JUnit - Test .

TestContextManager ist der Einstiegspunkt in das Spring TestContext- Framework und verwaltet daher den Zugriff auf Spring ApplicationContext und die Abhängigkeitsinjektion in einer JUnit-Testklasse. Mit SpringJUnit4ClassRunner können Entwickler daher Integrationstests für Spring-Komponenten wie Controller und Repositorys implementieren.

Zum Beispiel können wir einen Integrationstest für unseren RestController implementieren :

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = WebConfig.class) public class RoleControllerIntegrationTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; private static final String CONTENT_TYPE = "application/text;charset=ISO-8859-1"; @Before public void setup() throws Exception { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test public void givenEmployeeNameJohnWhenInvokeRoleThenReturnAdmin() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders .get("/role/John")) .andDo(print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) .andExpect(MockMvcResultMatchers.content().string("ADMIN")); } }

Wie aus dem Test hervorgeht, akzeptiert unser Controller einen Benutzernamen als Pfadparameter und gibt die Benutzerrolle entsprechend zurück.

Jetzt, um diesen REST - Service zu testen , mit einer anderen Benutzername / Rollenkombination, würden wir einen neuen Test durchführen müssen:

@Test public void givenEmployeeNameDoeWhenInvokeRoleThenReturnEmployee() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders .get("/role/Doe")) .andDo(print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) .andExpect(MockMvcResultMatchers.content().string("EMPLOYEE")); }

Dies kann bei Diensten, bei denen eine große Anzahl von Eingabekombinationen möglich ist, schnell außer Kontrolle geraten.

Um diese Art der Wiederholung in unseren Testklassen zu vermeiden, sehen wir uns an, wie Sie Parametrisiert zum Implementieren von JUnit-Tests verwenden, die mehrere Eingaben akzeptieren.

3. Verwenden von Parametriert

3.1. Parameter definieren

Parametrisiert ist ein benutzerdefinierter JUnit-Testläufer, mit dem wir einen einzelnen Testfall schreiben und ihn für mehrere Eingabeparameter ausführen lassen können:

@RunWith(Parameterized.class) @WebAppConfiguration @ContextConfiguration(classes = WebConfig.class) public class RoleControllerParameterizedIntegrationTest { @Parameter(value = 0) public String name; @Parameter(value = 1) public String role; @Parameters public static Collection data() { Collection params = new ArrayList(); params.add(new Object[]{"John", "ADMIN"}); params.add(new Object[]{"Doe", "EMPLOYEE"}); return params; } //... }

Wie oben gezeigt, haben wir die Annotation @Parameters verwendet , um die Eingabeparameter vorzubereiten, die in den JUnit-Test eingefügt werden sollen. Wir haben auch die Zuordnung dieser Werte im Namen und in der Rolle der @ Parameter- Felder bereitgestellt .

Aber jetzt müssen wir ein anderes Problem lösen: JUnit erlaubt nicht mehrere Läufer in einer JUnit-Testklasse . Dies bedeutet, dass wir SpringJUnit4ClassRunner nicht nutzen können , um den TestContextManager in unsere Testklasse einzubetten . Wir müssen einen anderen Weg finden, um TestContextManager einzubetten .

Glücklicherweise bietet Spring einige Optionen, um dies zu erreichen. Wir werden diese in den folgenden Abschnitten diskutieren.

3.2. Initialisieren des TestContextManager Manuell

Die erste Option ist recht einfach, da wir mit Spring TestContextManager manuell initialisieren können :

@RunWith(Parameterized.class) @WebAppConfiguration @ContextConfiguration(classes = WebConfig.class) public class RoleControllerParameterizedIntegrationTest { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; private TestContextManager testContextManager; @Before public void setup() throws Exception { this.testContextManager = new TestContextManager(getClass()); this.testContextManager.prepareTestInstance(this); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } //... }

In diesem Beispiel haben wir insbesondere den parametrisierten Runner anstelle des SpringJUnit4ClassRunner verwendet. Als Nächstes haben wir den TestContextManager in der setup () -Methode initialisiert .

Jetzt können wir unseren parametrisierten JUnit-Test implementieren:

@Test public void givenEmployeeNameWhenInvokeRoleThenReturnRole() throws Exception { this.mockMvc.perform(MockMvcRequestBuilders .get("/role/" + name)) .andDo(print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(CONTENT_TYPE)) .andExpect(MockMvcResultMatchers.content().string(role)); }

JUnit führt diesen Testfall zweimal aus - einmal für jeden Satz von Eingaben, die wir mithilfe der Annotation @Parameters definiert haben .

3.3. SpringClassRule und SpringMethodRule

Im Allgemeinen wird nicht empfohlen, den TestContextManager manuell zu initialisieren . Stattdessen empfiehlt Spring die Verwendung von SpringClassRule und SpringMethodRule.

SpringClassRule implementiert JUnits TestRule - eine alternative Methode zum Schreiben von Testfällen. TestRule kann verwendet werden, um die Setup- und Bereinigungsvorgänge zu ersetzen, die zuvor mit den Methoden @Before, @BeforeClass, @After und @AfterClass durchgeführt wurden.

SpringClassRule bettet Funktionen auf Klassenebene von TestContextManager in eine JUnit- Testklasse ein. Es initialisiert den TestContextManager und ruft die Einrichtung und Bereinigung des Spring TestContext auf. Daher bietet es Abhängigkeitsinjektion und Zugriff auf den ApplicationContext .

Zusätzlich zu SpringClassRule müssen wir auch SpringMethodRule verwenden . Hiermit werden Funktionen auf Instanzebene und Methodenebene für TestContextManager bereitgestellt.

SpringMethodRule ist für die Vorbereitung der Testmethoden verantwortlich. Außerdem wird nach Testfällen gesucht, die zum Überspringen markiert sind, und deren Ausführung verhindert.

Mal sehen, wie dieser Ansatz in unserer Testklasse verwendet wird:

@RunWith(Parameterized.class) @WebAppConfiguration @ContextConfiguration(classes = WebConfig.class) public class RoleControllerParameterizedClassRuleIntegrationTest { @ClassRule public static final SpringClassRule scr = new SpringClassRule(); @Rule public final SpringMethodRule smr = new SpringMethodRule(); @Before public void setup() throws Exception { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } //... }

4. Fazit

In diesem Artikel haben wir zwei Möglichkeiten zum Implementieren von Spring-Integrationstests mit dem parametrisierten Testläufer anstelle von SpringJUnit4ClassRunner erläutert . Wir haben gesehen, wie TestContextManager manuell initialisiert wird, und wir haben ein Beispiel mit SpringClassRule mit SpringMethodRule gesehen , dem von Spring empfohlenen Ansatz.

Obwohl wir in diesem Artikel nur den parametrisierten Läufer besprochen haben , können wir einen dieser Ansätze mit jedem JUnit-Läufer verwenden , um Spring-Integrationstests zu schreiben.

Wie üblich ist der gesamte Beispielcode auf GitHub verfügbar.