Integrasjonstesting om våren

1. Oversikt

Integrasjonstesting spiller en viktig rolle i programutviklingssyklusen ved å verifisere end-to-end oppførselen til et system.

I denne artikkelen vil vi se hvordan vi kan utnytte Spring MVC-testrammeverket for å skrive og kjøre integrasjonstester som tester kontrollere uten å eksplisitt starte en Servlet-container.

2. Forberedelse

Følgende Maven-avhengigheter er nødvendig for å kjøre integrasjonstester som beskrevet i denne artikkelen. Først og fremst de siste JUnit- og Spring-testavhengighetene:

 junit junit 4.12 test org.springframework spring-test 4.3.2.RELEASE test 

For å effektivisere resultatene, skal vi også bruke Hamcrest og JSON-banen:

 org.hamcrest hamcrest-library 1.3 test com.jayway.jsonpath json-path 2.2.0 test 

3. Vår-MVC-testkonfigurasjon

La oss nå introdusere hvordan du konfigurerer og kjører våraktiverte tester.

3.1. Aktiver vår i tester

Først vil enhver våraktivert test kjøres ved hjelp av @RunWith (SpringJUnit4ClassRunner.class); løperen er egentlig inngangsstedet for å begynne å bruke rammene for vårtest.

Vi trenger også @ContextConfiguration merknader for å laste inn kontekstkonfigurasjonen og bootstrap konteksten som testen vil bruke.

La oss se:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (klasser = {ApplicationConfig.class}) @WebAppConfiguration offentlig klasse GreetControllerIntegrationTest {....}

Legg merke til hvordan, i @ContextConfiguration, vi ga ApplicationConfig.class config klasse som laster inn konfigurasjonen vi trenger for denne spesielle testen.

Vi brukte en Java-konfigurasjonsklasse her for å spesifisere kontekstkonfigurasjonen; på samme måte kan vi bruke den XML-baserte konfigurasjonen:

@ContextConfiguration (locations = {""})

Til slutt - testen er også kommentert med @WebAppConfiguration - som vil laste inn webapplikasjonskonteksten.

Som standard ser det etter rotnettprogrammet på standardstien src / main / webapp; stedet kan overstyres ved å passere verdi attributt som:

@WebAppConfiguration (verdi = "")

3.2. De WebApplicationContext Gjenstand

WebApplicationContext (wac) gir en webapplikasjonskonfigurasjon. Den laster alle applikasjonsbønner og kontrollere i konteksten.

Vi kan nå koble nettapplikasjonskonteksten rett inn i testen:

@Autowired privat WebApplicationContext wac;

3.3. Mocking Web Context Beans

MockMvc gir støtte for Spring MVC testing. Den innkapsler alle bønner for webapplikasjoner og gjør dem tilgjengelige for testing.

La oss se hvordan du bruker det:

private MockMvc mockMvc; @Før offentlige ugyldige oppsett () kaster unntak {this.mockMvc = MockMvcBuilders.webAppContextSetup (this.wac) .build (); }

Vi må initialisere mockMvc objekt i @Før kommentert metode, slik at vi ikke trenger å initialisere den i hver test.

3.4. Bekreft testkonfigurasjon

For vår opplæring her, la oss faktisk bekrefte at vi laster inn WebApplicationContext objekt (wac) ordentlig. Vi vil også bekrefte at det er riktig servletContext blir festet:

@Test offentlig ugyldig givenWac_whenServletContext_thenItProvidesGreetController () {ServletContext servletContext = wac.getServletContext (); Assert.assertNotNull (servletContext); Assert.assertTrue (servletContext-forekomst av MockServletContext); Assert.assertNotNull (wac.getBean ("greetController")); }

Legg merke til at vi også sjekker at vi a GreetController.java bønne eksisterer i nettkonteksten - som sørger for at vårbønner lastes ordentlig.

På dette punktet er oppsettet av integrasjonstesten gjort. La oss se hvordan vi kan teste ressursmetoder ved hjelp av MockMvc gjenstand.

4. Skrive integrasjonstester

I denne delen vil vi gå gjennom de grunnleggende operasjonene som er tilgjengelige gjennom testrammeverket.

Vi viser hvordan du sender forespørsler med banevariabler og parametere. Vi vil også følge med noen få eksempler som viser hvordan du kan hevde at riktig visningsnavn er løst, eller at responsorganet er som forventet.

Følgende utdrag bruker statisk import fra MockMvcRequestBuilders eller MockMvcResultMatchers klasser.

4.1. Bekreft visningsnavn

La oss påkalle / homePage endepunkt fra testen vår som:

// localhost: 8080 / spring-mvc-test /

eller

// localhost: 8080 / spring-mvc-test / homePage

Kodebit:

@Test offentlig ugyldighet gittHomePageURI_whenMockMVC_thenReturnsIndexJSPViewName () {this.mockMvc.perform (get ("/ homePage")). Og gjør (skriv ut ()). Og Expect (vis (). Navn ("indeks")); }

La oss bryte ned det:

  • utføre() metoden vil kalle en få forespørselsmetode som returnerer ResultatAksjoner. Ved å bruke dette resultatet kan vi ha påstandsforventninger om respons som innhold, HTTP-status, overskrift osv
  • andDo (print ()) vil skrive ut forespørselen og svaret. Dette er nyttig for å få en detaljert oversikt i tilfelle feil
  • andExpect ()vil forvente det angitte argumentet. I vårt tilfelle forventer vi at "indeksen" skal returneres via MockMvcResultMatchers.view ()

4.2. Bekreft responsorganet

Vi vil påberope oss /hilse på endepunkt fra testen vår som:

// localhost: 8080 / spring-mvc-test / greet

Forventet utgang:

{"id": 1, "message": "Hello World !!!" }

Kodebit:

@Test offentlig ugyldig gittGreetURI_whenMockMVC_thenVerifyResponse () {MvcResult mvcResult = this.mockMvc.perform (get ("/ greet")) .andDo (print ()). AndExpect (status (). IsOk ()) .andExpect (jsonPath ("$) .message "). verdi (" Hello World !!! ")). og Retur (); Assert.assertEquals ("application / json; charset = UTF-8", mvcResult.getResponse (). GetContentType ()); }

La oss se nøyaktig hva som skjer:

  • andExpect (MockMvcResultMatchers.status (). isOk ())vil verifisere at svaret HTTP-status er Ok dvs. 200. Dette sikrer at forespørselen ble utført
  • andExpect (MockMvcResultMatchers.jsonPath (“$. melding”). verdi (“Hello World !!!”)) vil bekrefte at svarinnholdet samsvarer med argumentet “Hei Verden!!!“. Her brukte vi jsonPath som trekker ut svarinnhold og gir ønsket verdi
  • andReturn ()vil returnere MvcResult objekt som brukes når vi må verifisere noe som ikke er oppnåelig av biblioteket. Du kan se at vi har lagt til hevderEquals for å matche innholdstypen av respons som hentes fra MvcResult gjenstand

4.3. Send Forespørsel med banevariabel

Vi vil påberope oss / greetWithPathVariable / {name} endepunkt fra testen vår som:

// localhost: 8080 / spring-mvc-test / greetWithPathVariable / John

Forventet utgang:

{"id": 1, "message": "Hello World John !!!" }

Kodebit:

@Test offentlig ugyldig givenGreetURIWithPathVariable_whenMockMVC_thenResponseOK () {this.mockMvc .perform (get ("/ greetWithPathVariable / {name}", "John")) .andDo (print ()). AndExpect (status (). IsOk ()) og Expand. (content (). contentType ("application / json; charset = UTF-8")) .andExpect (jsonPath ("$. message"). verdi ("Hello World John !!!")); }

MockMvcRequestBuilders.get (“/ greetWithPathVariable / {name}”, “John”) vil sende forespørsel som “/ greetWithPathVariable / John“.

Dette blir lettere med hensyn til lesbarhet og å vite hva som er parametrene som er satt dynamisk i URL-en. Merk at vi kan overføre så mange baneparametere som nødvendig.

4.4. Sende Forespørsel med spørringsparametere

Vi påberoper oss / greetWithQueryVariable? name = {name} endepunkt fra testen vår som:

// localhost: 8080 / spring-mvc-test / greetWithQueryVariable? name = John% 20Doe

Forventet utgang:

{"id": 1, "message": "Hello World John Doe !!!" }

Kodebit:

@Test offentlig ugyldig gittGreetURIWithQueryParameter_whenMockMVC_thenResponseOK () {this.mockMvc.perform (get ("/ greetWithQueryVariable") .param ("name", "John Doe")). AndDo (print ()). AndExpect (status () is. )) .andExpect (content (). contentType ("application / json; charset = UTF-8")). andExpect (jsonPath ("$. message"). verdi ("Hello World John Doe !!!")); }

param ("navn", "John Doe") vil legge til søkeparameteren i be om. Det ligner på “ / greetWithQueryVariable? name = John% 20Doe“.

Spørringsparameteren kan også implementeres ved hjelp av URI-malstilen:

this.mockMvc.perform (get ("/ greetWithQueryVariable? name = {name}", "John Doe"));

4.5. Sende POST Be om

Vi vil påberope oss / greetWithPost endepunkt fra testen vår som:

// localhost: 8080 / spring-mvc-test / greetWithPost

Forventet utgang:

{"id": 1, "message": "Hello World !!!" }

Kodebit:

@Test offentlig ugyldig gittGreetURIWithPost_whenMockMVC_thenVerifyResponse () {this.mockMvc.perform (post ("/ greetWithPost")). Og Gjør (skriv ut ()). Og Expect (status (). IsOk ()). Og Expect (content () .contentType (" application / json; charset = UTF-8 ")). og Expect (jsonPath (" $. message "). verdi (" Hello World !!! ")); }

MockMvcRequestBuilders.post (“/ greetWithPost”) vil sende innleggsforespørselen. Banevariabler og spørringsparametere kan settes på en lignende måte som vi så tidligere, mens skjemadata kan settes via param () metode bare lik spørringsparameter som:

// localhost: 8080 / spring-mvc-test / greetWithPostAndFormData

Skjemadata:

id = 1; navn = John% 20Doe

Forventet utgang:

{"id": 1, "message": "Hello World John Doe !!!" }

Kodebit:

@Test offentlig ugyldig gittGreetURIWithPostAndFormData_whenMockMVC_thenResponseOK () {this.mockMvc.perform (post ("/ greetWithPostAndFormData"). Param ("id", "1") .param ("name", "John Doe")). Og Gjør (skriv ut (print) ogExpect (status (). isOk ()). andExpect (content (). contentType ("application / json; charset = UTF-8")). andExpect (jsonPath ("$. message"). verdi (" Hello World John Doe !!! ")). Og Expect (jsonPath (" $. Id "). Verdi (1)); }

I kodebiten ovenfor har vi lagt til to parametere som "1" og navnet "John Doe".

5. MockMvc Begrensninger

MockMvc gir et elegant og brukervennlig API for å ringe nettendepunkter og inspisere og hevde deres svar samtidig. Til tross for alle fordelene har den noen få begrensninger.

Først og fremst bruker den en underklasse av DispatcherServlet å håndtere testforespørsler. For å være mer spesifikk, TestDispatcherServlet er ansvarlig for å ringe kontrollere og utføre all den kjente vårmagi.

De MockMvc klasse pakker inn dette TestDispatcherServlet internt. Så hver gang vi sender en forespørsel ved hjelp av utføre() metode, MockMvc vil bruke det underliggende TestDispatcherServlet direkte. Derfor, det er ingen reelle nettverkstilkoblinger, og følgelig tester vi ikke hele nettverksstakken mens du bruker MockMvc.

Også,fordi Spring forbereder en falsk applikasjonskontekst for å spotte HTTP-forespørsler og svar, støtter den kanskje ikke alle funksjonene i en fullverdig Spring-applikasjon.

For eksempel støtter ikke dette mock-oppsettet HTTP-omdirigeringer. Dette virker kanskje ikke så viktig i begynnelsen. Spring Boot håndterer imidlertid noen feil ved å omdirigere den gjeldende forespørselen til /feil endepunkt. Så hvis vi bruker MockMvc, Vi kan ikke teste noen API-feil.

Som et alternativ til MockMvc, vi kan sette opp en mer reell applikasjonskontekstog bruk deretter RestTemplate eller til og med være trygg på å teste søknaden vår.

For eksempel er dette enkelt å bruke Spring Boot:

@RunWith (SpringRunner.class) @SpringBootTest (webEnvironment = RANDOM_PORT) offentlig klasse GreetControllerRealIntegrationTest {@LocalServerPort privat int-port; @Før offentlig ugyldig setUp () {RestAssured.port = port; } @Test offentlig ugyldig gittGreetURI_whenSendingReq_thenVerifyResponse () {given (). Get ("/ greet") .then () .statusCode (200); }}

På denne måten vil hver test lage en reell HTTP-forespørsel til applikasjonen som lytter til en tilfeldig TCP-port.

6. Konklusjon

I denne opplæringen implementerte vi noen enkle våraktiverte integrasjonstester.

Vi så også på WebApplicationContext og MockMVC objektoppretting som spilte en viktig rolle i å kalle sluttpunktene til applikasjonen.

Ser vi videre dekket vi hvordan vi kan sende og POST forespørsler med variasjoner av parameteroverføring og hvordan du verifiserer HTTP-svarstatus, overskrift og innhold.

Som en avsluttende bemerkning vurderte vi også noen begrensninger i MockMvc. Å vite disse begrensningene kan lede oss til å ta en informert beslutning om hvordan vi skal implementere testene våre.

Endelig er implementeringen av alle disse eksemplene og kodebiter tilgjengelig i GitHub.


$config[zx-auto] not found$config[zx-overlay] not found