SpringJUnit4ClassRunner gebruiken met Parameterized

1. Overzicht

In deze tutorial zullen we zien hoe we een Spring-integratietest geïmplementeerd in JUnit4 met een Geparametriseerd JUnit-testloper.

2. SpringJUnit4ClassRunner

SpringJUnit4ClassRunner is een implementatie van JUnit4's ClassRunner dat integreert Spring's TestContextManager in een JUnit-test.

TestContextManager is het toegangspunt tot de lente TestContext framework en beheert daarmee de toegang tot Spring ApplicationContext en afhankelijkheidsinjectie in een JUnit-testklasse. Dus, SpringJUnit4ClassRunner stelt ontwikkelaars in staat om integratietests te implementeren voor Spring-componenten zoals controllers en repositories.

We kunnen bijvoorbeeld een integratietest uitvoeren voor onze RestController:

@RunWith (SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration (classes = WebConfig.class) openbare klasse RoleControllerIntegrationTest {@Autowired private WebApplicationContext wac; privé MockMvc mockMvc; private static final String CONTENT_TYPE = "applicatie / tekst; charset = ISO-8859-1"; @Before public void setup () gooit Uitzondering {this.mockMvc = MockMvcBuilders.webAppContextSetup (this.wac) .build (); } @Test openbare leegte gegevenEmployeeNameJohnWhenInvokeRoleThenReturnAdmin () genereert uitzondering {this.mockMvc.perform (MockMvcRequestBuilders .get ("/ role / John")) .andDo (print ()) .andExpect (MockMvcResultMatchers.status (). Is. andExpect (MockMvcResultMatchers.content (). contentType (CONTENT_TYPE)) .andExpect (MockMvcResultMatchers.content (). string ("ADMIN")); }}

Zoals uit de test blijkt, is onze Controller accepteert een gebruikersnaam als padparameter en geeft de gebruikersrol dienovereenkomstig terug.

Nu, om deze REST-service te testen met een andere gebruikersnaam / rol-combinatie, zouden we een nieuwe test moeten implementeren:

@Test openbare leegte gegevenEmployeeNameDoeWhenInvokeRoleThenReturnEmployee () gooit uitzondering {this.mockMvc.perform (MockMvcRequestBuilders .get ("/ role / Doe")) .andDo (print ()) .andExpect (MockMvcResultMatchers.status ()). IsOverzicht (). (MockMvcResultMatchers.content (). ContentType (CONTENT_TYPE)) .andExpect (MockMvcResultMatchers.content (). String ("WERKNEMER")); }

Dit kan snel uit de hand lopen voor diensten waar een groot aantal invoercombinaties mogelijk is.

Laten we eens kijken hoe we dit kunnen gebruiken om dit soort herhaling in onze testlessen te voorkomen Geparametriseerd voor het implementeren van JUnit-tests die meerdere invoer accepteren.

3. Met behulp van Geparametriseerd

3.1. Parameters definiëren

Geparametriseerd is een aangepaste JUnit-testrunner waarmee we een enkele testcase kunnen schrijven en deze kunnen laten draaien tegen meerdere invoerparameters:

@RunWith (Parameterized.class) @WebAppConfiguration @ContextConfiguration (classes = WebConfig.class) openbare klasse RoleControllerParameterizedIntegrationTest {@Parameter (waarde = 0) openbare Stringnaam; @Parameter (waarde = 1) openbare String-rol; @Parameters openbare statische Verzamelingsgegevens () {Verzamelingsparameters = nieuwe ArrayList (); params.add (nieuw object [] {"John", "ADMIN"}); params.add (nieuw object [] {"Doe", "WERKNEMER"}); retourparameters; } // ...}

Zoals hierboven getoond, hebben we de @Parameters annotatie om de invoerparameters voor te bereiden die in de JUnit-test moeten worden geïnjecteerd. We hebben ook gezorgd voor het in kaart brengen van deze waarden in het @Parameter velden naam en rol.

Maar nu hebben we nog een probleem op te lossen - JUnit staat niet meerdere hardlopers toe in één JUnit-testklasse. Dit betekent we kunnen er geen misbruik van maken SpringJUnit4ClassRunner om het TestContextManagerin onze testklas. We zullen een andere manier moeten vinden om in te bedden TestContextManager.

Gelukkig biedt Spring een aantal opties om dit te bereiken. We bespreken deze in de volgende secties.

3.2. Initialiseren van het TestContextManager Handmatig

De eerste optie is vrij eenvoudig, omdat we met Spring kunnen initialiseren TestContextManager handmatig:

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

In dit voorbeeld hebben we met name de Geparametriseerd runner in plaats van de SpringJUnit4ClassRunner. Vervolgens hebben we het TestContextManager in de opstelling() methode.

Nu kunnen we onze geparametriseerde JUnit-test implementeren:

@Test openbare leegte gegevenEmployeeNameWhenInvokeRoleThenReturnRole () genereert uitzondering {this.mockMvc.perform (MockMvcRequestBuilders .get ("/ role /" + naam)) .andDo (print ()) .andExpect (MockMvcResultMatchers.status ()). IsOk (). andExpect (MockMvcResultMatchers.content (). contentType (CONTENT_TYPE)) .andExpect (MockMvcResultMatchers.content (). string (rol)); }

JUnit zal deze testcase twee keer uitvoeren - eenmaal voor elke set ingangen die we hebben gedefinieerd met behulp van de @Parameters annotatie.

3.3. SpringClassRule en SpringMethodRule

Over het algemeen, het wordt niet aanbevolen om het TestContextManager handmatig. In plaats daarvan raadt Spring aan om te gebruiken SpringClassRule en SpringMethodRule.

SpringClassRule implementeert JUnit's Testregel - een alternatieve manier om testcases te schrijven. Testregel kan worden gebruikt om de installatie- en opschoningsbewerkingen te vervangen die eerder werden uitgevoerd @Voordat, @BeforeClass, @Na, en @Na de les methoden.

SpringClassRule insluit functionaliteit op klassenniveau van TestContextManager in een JUnit-testklasse. Het initialiseert het TestContextManager en roept de opzet en opruiming van de lente op TestContext. Daarom biedt het afhankelijkheidsinjectie en toegang tot het ApplicationContext.

In aanvulling op SpringClassRule, we moeten ook gebruiken SpringMethodRule. die de functionaliteit op instantieniveau en methodniveau biedt voor TestContextManager.

SpringMethodRule is verantwoordelijk voor de voorbereiding van de testmethoden. Het controleert ook op testgevallen die zijn gemarkeerd om over te slaan en voorkomt dat ze worden uitgevoerd.

Laten we eens kijken hoe we deze aanpak kunnen gebruiken in onze testles:

@RunWith (Parameterized.class) @WebAppConfiguration @ContextConfiguration (classes = WebConfig.class) openbare klasse RoleControllerParameterizedClassRuleIntegrationTest {@ClassRule openbare statische finale SpringClassRule scr = nieuwe SpringClassRule (); @Rule openbare finale SpringMethodRule smr = nieuwe SpringMethodRule (); @Before public void setup () gooit Uitzondering {this.mockMvc = MockMvcBuilders.webAppContextSetup (this.wac) .build (); } // ...}

4. Conclusie

In dit artikel hebben we twee manieren besproken om Spring-integratietests te implementeren met behulp van de Geparametriseerd testloper in plaats van SpringJUnit4ClassRunner. We hebben gezien hoe te initialiseren TestContextManager handmatig, en we zagen een voorbeeld met SpringClassRule met SpringMethodRule, de aanpak die wordt aanbevolen door Spring.

Hoewel we alleen de Geparametriseerd loper in dit artikel, we kunnen elk van deze benaderingen eigenlijk gebruiken met elke JUnit-runner om Spring-integratietests te schrijven.

Zoals gewoonlijk is alle voorbeeldcode beschikbaar op GitHub.