Kevään MVC on yksi suosituimmista Java-kehyksistä yritys Java-sovellusten rakentamiseen, ja se soveltuu erittäin hyvin testaamiseen. Suunnittelullaan Spring MVC edistää huolenaiheiden erottamista ja kannustaa koodaamaan rajapintoja vastaan. Nämä ominaisuudet tekevät yhdessä Springin riippuvuusinjektioiden kanssa kevään sovellukset erittäin testattavissa.
Tämä opetusohjelma on toinen puoli johdannostani yksikötestaukseen JUnit 5: llä. Näytän sinulle, kuinka JUnit 5 integroidaan Springiin, ja sitten esitän sinulle kolme työkalua, joiden avulla voit testata Spring MVC -ohjaimia, -palveluja ja -tietovarastoja.
lataa Hae koodi Lataa lähdekoodi esimerkiksi tässä opetusohjelmassa käytetyistä sovelluksista. Luonut Steven Haines JavaWorldille.JUnit 5 integroidaan jouseen 5
Tässä opetusohjelmassa käytämme Mavenia ja Spring Bootia, joten ensimmäinen asia, joka meidän on tehtävä, on lisätä JUnit 5 -riippuvuus Maven POM -tiedostoon:
org.junit.jupiter junit-jupiter 5.6.0 -testi
Aivan kuten osassa 1, käytämme tässä esimerkissä Mockitoa. Joten meidän on lisättävä JUnit 5 Mockito -kirjasto:
org.mockito mockito-junit-jupiter 3.2.4 -testi
@ExtendWith ja SpringExtension-luokka
JUnit 5 määrittelee laajennusliittymä, jonka kautta luokat voivat integroitua JUnit-testeihin suorituksen elinkaaren eri vaiheissa. Voimme ottaa laajennukset käyttöön lisäämällä @ExtendWith
huomautus testiluokkiin ja määritettävä ladattava laajennusluokka. Laajennus voi tällöin toteuttaa useita takaisinsoittorajapintoja, joita käytetään koko testin elinkaaren ajan: ennen kuin kaikki testit suoritetaan, ennen kutakin testiä, jokaisen testiajon jälkeen ja kun kaikki testit on suoritettu.
Kevät määrittelee a KevätLaajennus
luokka, joka tilaa JUnit 5: n elinkaari-ilmoitukset "testikontekstin" luomiseksi ja ylläpitämiseksi. Muistathan, että Springin sovelluskonteksti sisältää kaikki kevätpavut sovelluksessa ja että se suorittaa riippuvuusinjektion yhdistääkseen sovelluksen ja sen riippuvuudet. Spring käyttää JUnit 5 -laajennusmallia ylläpitääkseen testin sovelluskontekstia, mikä tekee Spring-yksikön kirjoittamisen yksinkertaisesta.
Kun olemme lisänneet JUnit 5 -kirjaston Maven POM -tiedostoon, voimme käyttää SpringExtension.luokka
JUnit 5 -testiluokkien laajentamiseksi:
@ExtendWith (SpringExtension.class) -luokan MyTests {// ...}
Tässä tapauksessa esimerkki on Spring Boot -sovellus. Onneksi @SpringBootTest
merkinnässä on jo @ExtendWith (SpringExtension.class)
merkinnät, joten meidän tarvitsee vain sisällyttää @SpringBootTest
.
Lisätään Mockito-riippuvuus
Testataksemme jokaisen komponentin kunnolla erillään ja simuloidaksemme erilaisia skenaarioita, haluamme luoda jokaisen luokan riippuvuuksien pilkkaavat toteutukset. Tässä on Mockito. Sisällytä seuraava riippuvuus POM-tiedostoon lisätäksesi tukea Mockitolle:
org.mockito mockito-junit-jupiter 3.2.4 -testi
Kun olet integroinut JUnit 5: n ja Mockito-sovelluksen Spring-sovellukseesi, voit hyödyntää Mockitoa määrittämällä yksinkertaisesti Spring-pavun (kuten palvelun tai arkiston) testiluokassasi käyttämällä @MockBean
merkintä. Tässä on esimerkkimme:
@SpringBootTest julkisen luokan WidgetServiceTest {/ ** * Autowire palvelussa, jonka haluamme testata * / @Autowired private WidgetService -palvelu; / ** * Luo WidgetRepository-mallin toteutus * / @MockBean private WidgetRepository -tietovarasto; ...}
Tässä esimerkissä luomme pilkkaa WidgetRepository
sisällä meidän WidgetServiceTest
luokassa. Kun kevät näkee tämän, se yhdistää sen automaattisesti meidän WidgetService
jotta voimme luoda erilaisia skenaarioita testimenetelmissämme. Kukin testimenetelmä määrittää laitteen käyttäytymisen WidgetRepository
, esimerkiksi palauttamalla pyydetyt Widget
tai palauttamalla Valinnainen. Tyhjä ()
kyselylle, jolle tietoja ei löydy. Vietämme loppuosan tästä opetusohjelmasta tarkastelemalla esimerkkejä näiden tapojen konfiguroimisesta.
Kevään MVC-esimerkkisovellus
Kevätpohjaisten yksikkötestien kirjoittamiseen tarvitsemme sovelluksen, jolla niitä voidaan kirjoittaa. Onneksi voimme käyttää minun esimerkkisovellusta Kevät-sarja opetusohjelma "Mastering Spring framework 5, Part 1: Spring MVC." Käytin kyseisen opetusohjelman esimerkkisovellusta perussovelluksena. Muutin sitä vahvemmalla REST-sovellusliittymällä, jotta meillä olisi vielä muutama asia testattavaksi.
Esimerkkisovellus on Spring MVC -verkkosovellus, jossa on REST-ohjain, palvelukerros ja arkisto, joka käyttää Spring Data JPA: ta "widgetien" säilyttämiseen H2-muistitietokantaan ja sieltä. Kuva 1 on yleiskatsaus.
Steven HainesMikä on widget?
A Widget
on vain "juttu", jolla on tunnus, nimi, kuvaus ja versionumero. Tässä tapauksessa widgetimme merkitään JPA-merkinnöillä sen määrittelemiseksi kokonaisuudeksi. WidgetRestController
on kevään MVC-ohjain, joka muuntaa RESTful-sovellusliittymäkutsut suoritettaviksi toimiksi Widgetit
. WidgetService
on tavallinen kevätpalvelu, joka määrittelee yrityksen toiminnallisuuden Widgetit
. Lopuksi WidgetRepository
on Spring Data JPA -rajapinta, jolle Spring luo toteutuksen ajon aikana. Tarkistamme kunkin luokan koodin kirjoittaessamme testejä seuraavissa osioissa.
Yksikkö testaa kevätpalvelua
Aloitetaan tarkistamalla, kuinka kevät testataanpalvelu, koska se on helpoin testata MVC-sovelluksessamme. Tämän osan esimerkit antavat meille mahdollisuuden tutkia JUnit 5: n integraatiota Springiin ottamatta käyttöön uusia testauskomponentteja tai kirjastoja, vaikka teemme sen myöhemmin opetusohjelmassa.
Aloitamme tarkistamalla WidgetService
käyttöliittymä ja WidgetServiceImpl
luokka, jotka näkyvät luetteloissa 1 ja 2.
Listaus 1. Spring-käyttöliittymä (WidgetService.java)
paketti com.geekcap.javaworld.spring5mvcexample.service; tuo com.geekcap.javaworld.spring5mvcexample.model.Widget; tuo java.util.List; tuo java.util.Valinnainen; julkinen käyttöliittymä WidgetService {Valinnainen findById (pitkä id); Lista findAll (); Widget-tallennus (Widget-widget); void deleteById (pitkä tunnus); }
Listaus 2. Spring-palvelun toteutusluokka (WidgetServiceImpl.java)
paketti com.geekcap.javaworld.spring5mvcexample.service; tuo com.geekcap.javaworld.spring5mvcexample.model.Widget; tuo com.geekcap.javaworld.spring5mvcexample.repository.WidgetRepository; tuo com.google.common.collect.Lists; tuo org.springframework.stereotype.Service; tuo java.util.ArrayList; tuo java.util.List; tuo java.util.Valinnainen; @Service public class WidgetServiceImpl toteuttaa WidgetService {private WidgetRepository -tietovaraston; public WidgetServiceImpl (WidgetRepository-arkisto) {this.repository = arkisto; } @Override public Valinnainen findById (Long id) {return repository.findById (id); } @Override public list findAll () {return Lists.newArrayList (repository.findAll ()); } @Override public Widget save (Widget -widget) {// Kasvata versionumeroa widget.setVersion (widget.getVersion () + 1); // Tallenna widget arkistoon return repository.save (widget); } @Override public void deleteById (Long id) {repository.deleteById (id); }}
WidgetServiceImpl
on kevätpalvelu, johon on merkitty @Service
merkintä, jolla on WidgetRepository
johdotettu siihen rakentajansa kautta. findById ()
, findAll ()
ja deleteById ()
menetelmät ovat kaikki läpäisymenetelmiä taustalla oleville WidgetRepository
. Ainoa löytämäsi liiketoimintalogiikka sijaitsee Tallentaa()
menetelmä, joka kasvattaa version versiota Widget
kun se on tallennettu.
Testiluokka
Tämän luokan testaamiseksi meidän on luotava ja konfiguroitava pilkku WidgetRepository
, johdin se WidgetServiceImpl
ja johdot sitten WidgetServiceImpl
testiluokkaan. Onneksi se on paljon helpompaa kuin miltä se kuulostaa. Luettelossa 3 näkyy WidgetServiceTest
luokassa.
Listaus 3. Kevään huoltotestiluokka (WidgetServiceTest.java)
paketti com.geekcap.javaworld.spring5mvcexample.service; tuo com.geekcap.javaworld.spring5mvcexample.model.Widget; tuo com.geekcap.javaworld.spring5mvcexample.repository.WidgetRepository; tuo org.junit.jupiter.api.Assertions; tuo org.junit.jupiter.api.DisplayName; tuo org.junit.jupiter.api.Test; tuo org.junit.jupiter.api.extension.ExtendWith; tuo org.springframework.beans.factory.annotation.Autowired; tuo org.springframework.boot.test.context.SpringBootTest; tuo org.springframework.boot.test.mock.mockito.MockBean; tuo org.springframework.test.context.junit.jupiter.SpringExtension; tuo java.util.Arrays; tuo java.util.List; tuo java.util.Valinnainen; tuo staattinen org.mockito.Mockito.doReturn; tuo staattinen org.mockito.ArgumentMatchers.any; @SpringBootTest julkisen luokan WidgetServiceTest {/ ** * Autowire palvelussa, jonka haluamme testata * / @Autowired private WidgetService -palvelu; / ** * Luo WidgetRepository-mallin toteutus * / @MockBean private WidgetRepository -tietovarasto; @Test @DisplayName ("Test findById Success") void testFindById () {// Asenna pilkkivarastomme Widget-widget = uusi Widget (1l, "Widgetin nimi", "Kuvaus", 1); doReturn (Valinnainen. (widget)). milloin (arkisto) .findById (1 l); // Suorita palvelupuhelu Valinnainen returnWidget = service.findById (1l); // Vahvista vastaus Assertions.assertTrue (returnWidget.isPresent (), "Widgetiä ei löytynyt"); Assertions.assertSame (returnWidget.get (), widget, "Palautettu widget ei ollut sama kuin pilkka"); } @Test @DisplayName ("Test findById Not Found") void testFindByIdNotFound () {// Asenna pilkkivarastomme doReturn (Valinnainen.empty ()). Milloin (arkisto) .findById (1l); // Suorita palvelupuhelu Valinnainen returnWidget = service.findById (1l); // Vahvista vastaus Assertions.assertFalse (returnWidget.isPresent (), "Widgetiä ei löydy"); } @Test @DisplayName ("Test findAll") void testFindAll () {// Asenna pilkkivarastomme Widget-widget1 = uusi Widget (1l, "Widgetin nimi", "Description", 1); Widget-widget2 = uusi widget (2l, "Widget 2 Name", "Description 2", 4); doReturn (Arrays.asList (widget1, widget2)). milloin (arkisto) .findAll (); // Suorita palvelupyynnön luettelo -widgetit = service.findAll (); // Vahvista vastaus Assertions.assertEquals (2, widgetit.size (), "findAllin pitäisi palauttaa 2 widgetiä"); } @Test @DisplayName ("Test save widget") void testSave () {// Asenna pilkkivarastomme Widget-widget = uusi Widget (1l, "Widgetin nimi", "Kuvaus", 1); doReturn (widget). milloin (arkisto) .save (mikä tahansa ()); // Suorita palvelupuhelu Widget ReturnWidget = service.save (widget); // Vahvista vastaus Assertions.assertNotNull (returnWidget, "Tallennetun widgetin ei tule olla tyhjä"); Assertions.assertEquals (2, returnWidget.getVersion (), "Versiota tulisi lisätä"); }}
WidgetServiceTest
luokka on merkitty @SpringBootTest
merkintä, joka skannaa CLASSPATH
kaikille Spring-kokoonpanoluokille ja papuille ja määrittää Spring-sovelluskontekstin testiluokalle. Ota huomioon, että WidgetServiceTest
sisältää implisiittisesti myös @ExtendWith (SpringExtension.class)
merkinnät @SpringBootTest
merkintä, joka integroi testiluokan JUnit 5: een.
Testiluokassa käytetään myös Spring'sia @Autowired
huomautus automaattiseen kirjoittamiseen a WidgetService
testata vastaan, ja se käyttää Mockiton @MockBean
merkintä mallin luomiseksi WidgetRepository
. Tässä vaiheessa meillä on pilkka WidgetRepository
jonka voimme määrittää, ja todellinen WidgetService
pilkun kanssa WidgetRepository
johdotettu siihen.
Testataan kevätpalvelua
Ensimmäinen testimenetelmä, testFindById ()
, suorittaa WidgetService
on findById ()
menetelmä, jonka pitäisi palauttaa Valinnainen
joka sisältää a Widget
. Aloitamme luomalla a Widget
että haluamme WidgetRepository
palata. Sitten hyödynnämme Mockito-sovellusliittymää konfiguroimaan WidgetRepository :: findById
menetelmä. Mock-logiikkamme rakenne on seuraava:
doReturn (VALUE_TO_RETURN). kun (MOCK_CLASS_INSTANCE). MOCK_METHOD
Tässä tapauksessa sanomme: Palauta an Valinnainen
meidän Widget
kun arkisto on findById ()
menetelmä kutsutaan argumentilla 1 (kuten a pitkä
).
Seuraavaksi vetoamme WidgetService
on findById
menetelmä argumentilla 1. Vahvistamme sitten, että se on läsnä ja että palautettu Widget
on se, jonka konfiguroimme pilkkaa WidgetRepository
palata.