Testiranje u Spring Boot-u

1. Pregled

U ovom uputstvu ćemo pogledati pisanje testova pomoću okvira za podršku u Spring Boot-u. Obuhvatit ćemo jedinične testove koji se mogu izvoditi izolirano, kao i integracijske testove koji će pokrenuti kontekst Spring prije izvođenja testova.

Ako ste novi u Spring Boot-u, pogledajte naš uvod u Spring Boot.

2. Postavljanje projekta

Aplikacija koju ćemo koristiti u ovom članku je API koji pruža neke osnovne operacije na Zaposlenik Resurs. Ovo je tipična razina arhitekture - API poziv obrađuje se iz Kontroler do Servis prema Upornost sloj.

3. Ovisnosti Mavena

Prvo dodajmo ovisnosti o testiranju:

 test org.springframework.boot test opruge-boot-starter-test 2.2.6.OSPUSTI com.h2database h2 test 

The proljetni-boot-starter-test je primarna ovisnost koja sadrži većinu elemenata potrebnih za naša ispitivanja.

H2 DB je naša baza podataka u memoriji. Eliminira potrebu za konfiguriranjem i pokretanjem stvarne baze podataka u svrhu ispitivanja.

4. Integracijsko ispitivanje s @DataJpaTest

Radit ćemo s entitetom pod nazivom Zaposlenik, koja ima iskaznica i a Ime kao njegova svojstva:

@Entity @Table (name = "person") zaposlenik javne klase {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; @Size (min = 3, max = 20) naziv privatnog niza; // standardni getteri i postavljači, konstruktori}

I evo našeg spremišta koje koristi Spring Data JPA:

@Repository javno sučelje EmployeeRepository proširuje JpaRepository {public Employee findByName (naziv niza); }

To je to za kôd sloja postojanosti. Krenimo sada prema pisanju naše probne nastave.

Prvo, kreirajmo kostur naše testne klase:

@RunWith (SpringRunner.class) @DataJpaTest javna klasa EmployeeRepositoryIntegrationTest {@Autowired private TestEntityManager entityManager; @Autowired privatni EmployeeRepository workerRepository; // ovdje napišite testne slučajeve}

@RunWith (SpringRunner.class) pruža most između značajki probnog pokretanja i JUnit-a. Kad god koristimo bilo koju značajku testiranja Spring Boot u našim JUnit testovima, bit će potrebna ova napomena.

@DataJpaTest pruža neke standardne postavke potrebne za testiranje sloja postojanosti:

  • konfiguriranje H2, baze podataka u memoriji
  • postavljanje hibernacije, proljetnih podataka i Izvor podataka
  • izvođenje an @EntityScan
  • uključivanje SQL zapisnika

Da bismo izvršili DB operacije, trebaju nam neki zapisi koji su već u našoj bazi podataka. Da bismo postavili ove podatke, možemo koristiti TestEntityManager.

Proljetna čizma TestEntityManager je alternativa standardnom JPA EntityManager koji pruža metode uobičajene za pisanje testova.

Spremište zaposlenika je komponenta koju ćemo testirati.

Sada napišite svoj prvi testni slučaj:

@Test public void whenFindByName_thenReturnE Employee () {// dao zaposlenik alex = novi zaposlenik ("alex"); entityManager.persist (alex); entityManager.flush (); // kada je zaposlenik pronađen = workerRepository.findByName (alex.getName ()); // zatim assertThat (found.getName ()) .isEqualTo (alex.getName ()); }

U gore navedenom testu koristimo TestEntityManager za umetanje Zaposlenik u DB-u i čitajući ga putem API-ja find by name.

The tvrditi da (...) dio dolazi iz knjižnice Assertj, koja dolazi u paketu s Spring Bootom.

5. Ruganje sa @MockBean

Naše Servis kod sloja ovisi o našem Spremište.

Međutim, za testiranje Servis sloj, ne trebamo znati ili se brinuti o tome kako se implementira sloj postojanosti:

@Service javna klasa EmployeeServiceImpl implementira EmployeeService {@Autowired private EmployeeRepository workerRepository; @Override public Employee getEfficieeByName (ime niza) {return workerRepository.findByName (name); }}

U idealnom slučaju, trebali bismo moći pisati i testirati svoje Servis kôd sloja bez ožičenja u našem punom postojanom sloju.

Da biste to postigli, možemo koristiti podrugljivu podršku koju pruža Spring Boot Test.

Prvo pogledajmo kostur testne klase:

@RunWith (SpringRunner.class) javna klasa EmployeeServiceImplIntegrationTest {@TestConfiguration statička klasa EmployeeServiceImplTestContextConfiguration {@Bean public EmployeeService workerService () {return new EmployeeServiceImpl (); }} @Autowired private EmployeeService workerService; @MockBean private EmployeeRepository workerRepository; // ovdje napišite testne slučajeve}

Da biste provjerili Servis klase, moramo imati instancu Servis razred stvoren i dostupan kao @Grah kako bismo mogli @Autowire to u našem testu. Ovu konfiguraciju možemo postići pomoću @TestConfiguration bilješka.

Tijekom skeniranja komponenata mogli bismo otkriti da se komponente ili konfiguracije stvorene samo za određene testove slučajno svugdje pokupe. Da biste to spriječili, Spring Boot nudi @TestConfiguration napomena koju možemo dodati na predavanjima u src / test / java ukazujući na to da ih skeniranjem ne treba podizati.

Još jedna zanimljiva stvar ovdje je upotreba @MockBean. Stvara rugalicu za Spremište zaposlenika, koji se može koristiti za zaobilaženje poziva na stvarni Spremište zaposlenika:

@Before public void setUp () {Zaposlenik alex = novi zaposlenik ("alex"); Mockito.when (workerRepository.findByName (alex.getName ())). ThenReturn (alex); }

Budući da je postavljanje završeno, testni slučaj bit će jednostavniji:

@Test public void whenValidName_thenEfficieeShouldBeFound () {String name = "alex"; Pronađen zaposlenik = workerService.getEfficieeByName (ime); assertThat (found.getName ()) .isEqualTo (ime); }

6. Jedinstveno testiranje sa @WebMvcTest

Naše Kontroler ovisi o Servis sloj; uključimo samo jednu metodu radi jednostavnosti:

@RestController @RequestMapping ("/ api") javna klasa EmployeeRestController {@Autowired private EmployeeService workerService; @GetMapping ("/ zaposlenici") javni popis getAllEfficiees () {povratak workerService.getAllEfficiees (); }}

Budući da smo usredotočeni samo na Kontroler koda, prirodno je ismijavati Servis kôd sloja za naše jedinične testove:

@RunWith (SpringRunner.class) @WebMvcTest (EmployeeRestController.class) javna klasa EmployeeRestControllerIntegrationTest {@Autowired private MockMvc mvc; @MockBean privatna usluga EmployeeService; // ovdje napišite testne slučajeve}

Za testiranje Kontroleri, možemo koristiti @WebMvcTest. Automatski će konfigurirati Spring MVC infrastrukturu za naše jedinične testove.

U većini slučajeva, @WebMvcTest bit će ograničen na bootstrap jednog kontrolera. Također ga možemo koristiti zajedno s @MockBean pružiti lažne implementacije za sve potrebne ovisnosti.

@WebMvcTest također automatski konfigurira MockMvc, koji nudi moćan način jednostavnog testiranja MVC kontrolera bez pokretanja punog HTTP poslužitelja.

Rekavši to, napišimo svoj testni slučaj:

@Test javna praznina givenEfficiees_whenGetEfficiees_thenReturnJsonArray () baca izuzetak {zaposlenik alex = novi zaposlenik ("alex"); Navedi sve zaposlenike = Arrays.asList (alex); dao (service.getAllEfficiees ()). willReturn (allEfficiees); mvc.perform (get ("/ api / zaposlenici") .contentType (MediaType.APPLICATION_JSON)) .andExpect (status (). isOk ()) .andExpect (jsonPath ("$", hasSize (1))) .andExpect ( jsonPath ("$ [0] .name", je (alex.getName ()))); }

The dobiti(…) poziv metode može se zamijeniti drugim metodama koje odgovaraju HTTP glagolima poput staviti(), objaviti ()itd. Imajte na umu da u zahtjevu postavljamo i vrstu sadržaja.

MockMvc je fleksibilan i pomoću njega možemo stvoriti bilo koji zahtjev.

7. Integracijsko testiranje sa @SpringBootTest

Kao što i samo ime govori, integracijski testovi usredotočeni su na integriranje različitih slojeva aplikacije. To također znači da nije riječ o ruganju.

Idealno bi bilo da integracijske testove držimo odvojeno od unit testova i ne bismo ih trebali izvoditi zajedno s unit testovima. To možemo učiniti upotrebom drugog profila za pokretanje samo integracijskih testova. Nekoliko razloga za to može biti da su integracijski testovi dugotrajni i možda će im trebati stvarna baza podataka za izvršenje.

Međutim, u ovom se članku nećemo usredotočiti na to, već ćemo upotrijebiti H2 trajnu pohranu u memoriji.

Integracijski testovi trebaju pokrenuti spremnik za izvršavanje testnih slučajeva. Stoga je za to potrebno neko dodatno postavljanje - sve je to jednostavno u Spring Boot-u:

@RunWith (SpringRunner.class) @SpringBootTest (SpringBootTest.WebEnvironment.MOCK, classes = Application.class) @AutoConfigureMockMvc @TestPropertySource (locations = "classpath: application-integrationtest.properties") public class EmployeeRestContrvIntMorTerentMentMontRavTontErTontErTontErTontErTontRontErTontErTontRontErTontRontRontErTontRontErTontErTontRontControl @Automobilsko privatno spremište EmployeeRepository; // ovdje napišite testne slučajeve}

The @SpringBootTest napomena je korisna kada trebamo pokrenuti cijeli spremnik. Napomena djeluje stvaranjem datoteke ApplicationContext koji će se koristiti u našim testovima.

Možemo koristiti webEnvironment atribut @SpringBootTest za konfiguriranje našeg runtime okruženja; koristimo WebEnvironment.MOCK ovdje tako da će spremnik raditi u lažnom servlet okruženju.

Dalje, @TestPropertySource napomena pomaže u konfiguriranju mjesta datoteka svojstava specifičnih za naše testove. Imajte na umu da je datoteka svojstva učitana sa @TestPropertySource nadjačat će postojeće primjena.svojstva datoteka.

The test primjene- integracija.svojstva sadrži detalje za konfiguriranje trajne pohrane:

spring.datasource.url = jdbc: h2: mem: test spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect

Ako želimo pokrenuti naše integracijske testove protiv MySQL-a, možemo promijeniti gornje vrijednosti u datoteci svojstava.

Test slučajevi za integracijske testove mogli bi izgledati slično kao Kontroler ispitivanja slojevitih jedinica:

@Test javna praznina givenEfficiees_whenGetEfficiees_thenStatus200 () baca iznimku {createTestEfficiee ("bob"); mvc.perform (get ("/ api / zaposlenici") .contentType (MediaType.APPLICATION_JSON)) .andExpect (status (). isOk ()) .andExpect (content () .contentTypeCompatibleWith (MediaType.APPLICATION_JSON)) .andExPathct ("$ [0] .name", je ("bob"))); }

Razlika od Kontroler Jedinstveni testovi sloja su da se ovdje ništa ne ruga i da će se izvršiti scenariji od kraja do kraja.

8. Automatski konfigurirani testovi

Jedna od nevjerojatnih značajki automatski konfiguriranih napomena Spring Boota je da pomaže učitavanju dijelova cjelovite aplikacije i slojeva baze podataka specifičnih za test.

Uz gore spomenute napomene, evo popisa nekoliko široko korištenih napomena:

  • @WebFluxTest: Možemo koristiti @WebFluxTest napomena za testiranje Spring WebFlux kontrolera. Često se koristi uz @MockBean pružiti lažne implementacije za potrebne ovisnosti.
  • @JdbcTest: Wmogu koristiti @JdbcTest napomena za testiranje JPA aplikacija, ali to je za testove koji zahtijevaju samo Izvor podataka. Bilješka konfigurira ugrađenu bazu podataka u memoriju i JdbcTemplate.
  • @JooqTest: Za testiranje testova povezanih s jOOQ-om možemo koristiti @JooqTest napomena koja konfigurira DSLContext.
  • @DataMongoTest: Za testiranje MongoDB aplikacija, @DataMongoTest je korisna napomena. Prema zadanim postavkama konfigurira ugrađeni MongoDB u memoriju ako je upravljački program dostupan putem ovisnosti, konfigurira MongoPredložak, skenira za @Dokument klase i konfigurira spremišta Spring Data MongoDB.
  • @DataRedisTestolakšava testiranje aplikacija Redis. Skenira za @RedisHash klase i prema zadanim postavkama konfigurira spremišta Spring Data Redis.
  • @DataLdapTest konfigurira ugrađenu memoriju LDAP (ako je dostupno), konfigurira a LdapTemplate, skenira za @ Ulaz klase i konfigurira Spring Data LDAP spremišta prema zadanim postavkama.
  • @RestClientTest: Obično koristimo @RestClientTest napomena za testiranje REST klijenata. Automatski konfigurira različite ovisnosti kao što su podrška za Jackson, GSON i Jsonb; konfigurira a RestTemplateBuilder; i dodaje podršku za MockRestServiceServer prema zadanim postavkama.

9. Zaključak

U ovom smo članku duboko zarobili podršku za testiranje u Spring Boot-u i pokazali kako učinkovito pisati unit testove.

Kompletni izvorni kôd ovog članka nalazi se na GitHubu. Izvorni kod sadrži mnogo više primjera i raznih test slučajeva.

A ako želite nastaviti učiti o testiranju, u JUnit 5 imamo zasebne članke vezane uz integracijske testove i jedinične testove.