Integracijsko testiranje u proljeće

1. Pregled

Integracijsko testiranje igra važnu ulogu u ciklusu razvoja aplikacija provjeravanjem ponašanja sustava od kraja do kraja.

U ovom ćemo članku vidjeti kako možemo iskoristiti Spring MVC testni okvir kako bismo napisali i pokrenuli integracijske testove koji testiraju kontrolere bez eksplicitnog pokretanja spremnika Servlet.

2. Priprema

Sljedeće Mavenove ovisnosti potrebne su za pokretanje integracijskih testova kako je opisano u ovom članku. Prvo i najvažnije najnovije JUnit i Spring test ovisnosti:

 test junit junit 4.12 ispit org.springframework opruga-test 4.3.2.Opusti test 

Za učinkovito utvrđivanje rezultata, također ćemo koristiti Hamcrest i JSON put:

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

3. Proljetna konfiguracija MVC testa

Hajde sada da predstavimo kako konfigurirati i pokrenuti testove s omogućenim proljećem.

3.1. Omogućite proljeće u testovima

Prvo, bilo koji test omogućen za proljeće pokrenut će se uz pomoć @RunWith (SpringJUnit4ClassRunner.class); trkač je u osnovi polazna točka za početak korištenja okvira Spring Test.

Također nam je potreban @ContextConfiguration napomene za učitavanje konfiguracije konteksta i bootstrap kontekst koji će test koristiti.

Pogledajmo:

@RunWith (SpringJUnit4ClassRunner.class) @ContextConfiguration (classes = {ApplicationConfig.class}) @WebAppConfiguration javna klasa GreetControllerIntegrationTest {....}

Primijetite kako, u @ContextConfiguration, osigurali smo ApplicationConfig.class klasa config koja učitava konfiguraciju koja nam je potrebna za ovaj određeni test.

Ovdje smo koristili klasu Java konfiguracije za određivanje konfiguracije konteksta; slično, možemo koristiti XML-zasnovanu konfiguraciju:

@ContextConfiguration (lokacije = {""})

Konačno - test je također označen s @WebAppConfiguration - koji će učitati kontekst web aplikacije.

Prema zadanim postavkama traži korijensku web aplikaciju na zadanom putu src / main / webapp; mjesto se može nadjačati dodavanjem vrijednost atribut kao:

@WebAppConfiguration (vrijednost = "")

3.2. The WebApplicationContext Objekt

WebApplicationContext (wac) pruža konfiguraciju web aplikacije. Učitava sve grah aplikacija i kontrolere u kontekst.

Sad ćemo kontekst web aplikacije moći povezati izravno u test:

@Autowired private WebApplicationContext wac;

3.3. Podrugljivi grah iz konteksta weba

MockMvc pruža podršku za proljetno MVC testiranje. Inkapsulira sve grahove web aplikacija i čini ih dostupnima za testiranje.

Pogledajmo kako ga koristiti:

privatni MockMvc mockMvc; @Prije javnog void postavljanja () baca iznimku {this.mockMvc = MockMvcBuilders.webAppContextSetup (this.wac) .build (); }

Moramo inicijalizirati mockMvc objekt u @Prije anotirana metoda, tako da je ne trebamo inicijalizirati unutar svakog testa.

3.4. Provjerite testnu konfiguraciju

Za naš tutorial ovdje, provjerimo zapravo li učitavamo WebApplicationContext objekt (wac) pravilno. Također ćemo provjeriti je li to pravo servletContext se prilaže:

@Test javna praznina givenWac_whenServletContext_thenItProvidesGreetController () {ServletContext servletContext = wac.getServletContext (); Assert.assertNotNull (servletContext); Assert.assertTrue (instanca servletContext MockServletContext); Assert.assertNotNull (wac.getBean ("greetController")); }

Primijetimo da također provjeravamo jesmo li GreetController.java bean postoji u internetskom kontekstu - što osigurava ispravno učitavanje proljetnog graha.

U ovom je trenutku završeno postavljanje integracijskog testa. Pogledajmo kako možemo testirati metode resursa pomoću MockMvc objekt.

4. Pisanje integracijskih testova

U ovom ćemo odjeljku razmotriti osnovne operacije dostupne kroz testni okvir.

Pokazat ćemo kako slati zahtjeve s varijablama i parametrima puta. Također ćemo slijediti nekoliko primjera koji pokazuju kako tvrditi da je ispravno ime pogleda riješeno ili da je tijelo odgovora onako kako se očekivalo.

Sljedeći isječci koriste statički uvoz iz MockMvcRequestBuilders ili MockMvcResultMatchers razreda.

4.1. Potvrdite naziv pogleda

Zazovimo / homePage krajnja točka iz našeg testa kao:

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

ili

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

Isječak koda:

@Test javna praznina givenHomePageURI_whenMockMVC_thenReturnsIndexJSPViewName () {this.mockMvc.perform (get ("/ homePage")). AndDo (print ()) .andExpect (view (). Name ("index")); }

Razdvojimo to:

  • izvesti () metoda pozvat će metodu zahtjeva za dobivanje koja vraća RezultatAkcije. Korištenjem ovog rezultata možemo očekivati ​​tvrdnje o odgovoru poput sadržaja, HTTP statusa, zaglavlja itd
  • andDo (ispis ()) ispisat će zahtjev i odgovor. Ovo je korisno za detaljan prikaz u slučaju pogreške
  • andExpect ()očekivat će navedeni argument. U našem slučaju očekujemo da se "indeks" vrati putem MockMvcResultMatchers.view ()

4.2. Provjerite tijelo za odgovor

Pozvat ćemo se /pozdraviti krajnja točka iz našeg testa kao:

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

Očekivani izlaz:

{"id": 1, "message": "Pozdrav svijetu !!!" }

Isječak koda:

@Test javna praznina givenGreetURI_whenMockMVC_thenVerifyResponse () {MvcResult mvcResult = this.mockMvc.perform (get ("/ greet") .andDo (print ()). AndExpect (status (). IsOk ()). .message "). value (" Hello World !!! ")) .andReturn (); Assert.assertEquals ("application / json; charset = UTF-8", mvcResult.getResponse (). GetContentType ()); }

Da vidimo točno što se događa:

  • andExpect (MockMvcResultMatchers.status (). isOk ())će provjeriti je li HTTP status odgovora U redu tj. 200. To osigurava uspješno izvršavanje zahtjeva
  • andExpect (MockMvcResultMatchers.jsonPath ("$. message"). value ("Hello World !!!")) provjerit će da li se sadržaj odgovora podudara s argumentom „Pozdrav svijete!!!“. Ovdje smo koristili jsonPath koja izdvaja sadržaj odgovora i daje traženu vrijednost
  • i vratiti()vratit će MvcResult objekt koji se koristi kada moramo provjeriti nešto što knjižnica ne može postići. Vidite da smo dodali assertEquals kako bi odgovarao vrsti odgovora sadržaja koja je izvučena iz MvcResult objekt

4.3. Pošaljite DOBITI Zahtjev s varijablom puta

Pozvat ćemo se / greetWithPathVariable / {name} krajnja točka iz našeg testa kao:

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

Očekivani izlaz:

{"id": 1, "message": "Pozdrav svijete Johne !!!" }

Isječak koda:

@Test javna praznina givenGreetURIWithPathVariable_whenMockMVC_thenResponseOK () {this.mockMvc .perform (get ("/ greetWithPathVariable / {name}", "John")). (content (). contentType ("application / json; charset = UTF-8")) .andExpect (jsonPath ("$. message"). value ("Hello World John !!!")); }

MockMvcRequestBuilders.get (“/ greetWithPathVariable / {name}”, “John”) poslat će zahtjev kao “/ greetWithPathVariable / John“.

To postaje lakše s obzirom na čitljivost i znanje koji su parametri koji se dinamički postavljaju u URL-u. Imajte na umu da možemo proslijediti onoliko parametara puta koliko je potrebno.

4.4. Poslati DOBITI Zahtjev s parametrima upita

Pozvat ćemo se / greetWithQueryVariable? name = {ime} krajnja točka iz našeg testa kao:

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

Očekivani izlaz:

{"id": 1, "message": "Pozdrav svijetu John Doe !!!" }

Isječak koda:

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

param ("ime", "John Doe") će dodati parametar upita u DOBITI zahtjev. Slično je " / greetWithQueryVariable? name = John% 20Dee“.

Parametar upita također se može implementirati koristeći stil URI predloška:

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

4.5. Poslati OBJAVI Zahtjev

Pozvat ćemo se / greetWithPost krajnja točka iz našeg testa kao:

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

Očekivani izlaz:

{"id": 1, "message": "Pozdrav svijetu !!!" }

Isječak koda:

@Test javna praznina givenGreetURIWithPost_whenMockMVC_thenVerifyResponse () {this.mockMvc.perform (post ("/ greetWithPost")). AndDo (print ()) .andExpect (status (). IsOk ()). AndExpect (content ()). application / json; charset = UTF-8 ")) .andExpect (jsonPath (" $. message "). value (" Hello World !!! ")); }

MockMvcRequestBuilders.post (“/ greetWithPost”) poslat će zahtjev za poštu. Varijable puta i parametri upita mogu se postaviti na sličan način na koji smo gledali ranije, dok se podaci obrasca mogu postaviti putem param () metoda slična samo parametru upita kao:

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

Podaci obrasca:

id = 1; name = John% 20Dee

Očekivani izlaz:

{"id": 1, "message": "Zdravo, John Doe !!!" }

Isječak koda:

@Test public void givenGreetURIWithPostAndFormData_whenMockMVC_thenResponseOK () {this.mockMvc.perform (post ("/ greetWithPostAndFormData"). Param ("id", "1") .param ("name", "John Doe"). )). andExpect (status (). isOk ()) .andExpect (content (). contentType ("application / json; charset = UTF-8")) .andExpect (jsonPath ("$. message"). value (" Pozdrav svijetu John Doe !!! ")) .andExpect (jsonPath (" $. Id "). Value (1)); }

U gornji isječak koda dodali smo dva parametra id kao "1" i naziv kao "John Doe".

5. MockMvc Ograničenja

MockMvc pruža elegantan i jednostavan za korištenje API-ja za istovremeno pozivanje web krajnjih točaka i pregled i utvrđivanje njihovog odgovora. Unatoč svim blagodatima, ima nekoliko ograničenja.

Prije svega, koristi podklasu DispatcherServlet za obradu zahtjeva za ispitivanje. Da budemo precizniji, TestDispatcherServlet odgovoran je za pozivanje kontrolora i izvođenje svih poznatih proljetnih čarolija.

The MockMvc razred ovo obavija TestDispatcherServlet iznutra. Dakle, svaki put kad pošaljemo zahtjev pomoću izvesti () metoda, MockMvc koristit će temeljni TestDispatcherServlet direktno. Stoga, nema uspostavljenih stvarnih mrežnih veza, i slijedom toga, nećemo testirati cijeli mrežni stog tijekom upotrebe MockMvc.

Također,jer Spring priprema lažni kontekst web aplikacije za izrugivanje HTTP zahtjeva i odgovora, možda neće podržati sve značajke potpuno razvijene aplikacije Spring.

Na primjer, ova lažna postavka ne podržava HTTP preusmjeravanja. U početku se ovo možda ne čini toliko značajnim. Međutim, Spring Boot rješava neke pogreške preusmjeravanjem trenutnog zahtjeva na / pogreška krajnja točka. Dakle, ako koristimo MockMvc, možda nećemo moći testirati neke API greške.

Kao alternativa MockMvc, možemo postaviti stvarniji kontekst aplikacijea zatim upotrijebite RestTemplate ili čak budite sigurni da ćete testirati našu aplikaciju.

Na primjer, ovo je lako koristiti Spring Boot:

@RunWith (SpringRunner.class) @SpringBootTest (webEnvironment = RANDOM_PORT) javna klasa GreetControllerRealIntegrationTest {@LocalServerPort private int port; @Before public void setUp () {RestAssured.port = port; } @Test javna praznina givenGreetURI_whenSendingReq_thenVerifyResponse () {given (). Get ("/ greet"). Then () .statusCode (200); }}

Na taj će način svaki test poslati pravi HTTP zahtjev aplikaciji koja preslušava na slučajnom TCP priključku.

6. Zaključak

U ovom smo vodiču implementirali nekoliko jednostavnih testova integracije koji su omogućili Spring.

Također smo pogledali WebApplicationContext i MockMVC stvaranje objekata koje je igralo važnu ulogu u pozivanju krajnjih točaka aplikacije.

Gledajući dalje, pokrili smo kako možemo poslati DOBITI i OBJAVI zahtjevi s varijacijama prosljeđivanja parametara i kako provjeriti status, zaglavlje i sadržaj HTTP odgovora.

Kao završnu napomenu, također smo procijenili neka ograničenja MockMvc. Poznavanje tih ograničenja može nas voditi do informirane odluke o tome kako ćemo primijeniti naše testove.

Napokon, implementacija svih ovih primjera i isječaka koda dostupna je u GitHubu.