Testing i vårstøvel

1. Oversikt

I denne veiledningen tar vi en titt på skrive tester ved hjelp av rammestøtten i Spring Boot. Vi vil dekke enhetstester som kan kjøre isolert, samt integrasjonstester som vil starte opp vårkonteksten før du utfører tester.

Hvis du ikke er kjent med Spring Boot, sjekk ut introduksjonen til Spring Boot.

2. Prosjektoppsett

Applikasjonen vi skal bruke i denne artikkelen er et API som gir noen grunnleggende operasjoner på en Ansatt Ressurs. Dette er en typisk lagdelt arkitektur - API-samtalen behandles fra Kontroller til Service til Standhaftighet lag.

3. Maven-avhengigheter

La oss først legge til våre testavhengigheter:

 org.springframework.boot spring-boot-starter-test test 2.2.6.RELEASE com.h2database h2 test 

De vår-støvel-start-test er den primære avhengigheten som inneholder flertallet av elementene som kreves for testene våre.

H2 DB er vår minne-database. Det eliminerer behovet for å konfigurere og starte en faktisk database for testformål.

4. Integrasjonstesting med @DataJpaTest

Vi skal jobbe med en enhet som heter Ansatt, som har en id og en Navn som dens egenskaper:

@Entity @Table (name = "person") offentlig klasse Ansatt {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat Lang id; @Size (min = 3, max = 20) privat strengnavn; // standard getters og setters, konstruktører}

Og her er vårt depot ved hjelp av Spring Data JPA:

@Repository offentlig grensesnitt EmployeeRepository utvider JpaRepository {offentlig ansatt findByName (strengnavn); }

Det er det for utholdenhetskodekoden. La oss nå gå mot å skrive testklassen vår.

La oss først lage skjelettet til testklassen vår:

@RunWith (SpringRunner.class) @DataJpaTest offentlig klasse EmployeeRepositoryIntegrationTest {@Autowired private TestEntityManager entityManager; @Autowired private EmployeeRepository ansatteRepository; // skriv prøvesaker her}

@RunWith (SpringRunner.class) gir en bro mellom Spring Boot testfunksjoner og JUnit. Når vi bruker Spring Boot-testfunksjoner i JUnit-testene, vil denne kommentaren være påkrevd.

@DataJpaTest gir noen standardoppsett som trengs for å teste utholdenhetslaget:

  • konfigurere H2, en database i minnet
  • innstilling av dvalemodus, vårdata og Datakilde
  • utfører en @EntityScan
  • slå på SQL-logging

For å utføre DB-operasjoner trenger vi noen poster som allerede er i databasen vår. For å sette opp disse dataene kan vi bruke TestEntityManager.

Vårstøvelen TestEntityManager er et alternativ til standard JPA EntityManager som gir metoder som ofte brukes når du skriver tester.

Ansattes depot er komponenten vi skal teste.

La oss nå skrive vår første testsak:

@Test offentlig ugyldig når FindByName_thenReturnEmployee () {// gitt ansatt alex = ny ansatt ("alex"); entityManager.persist (alex); entityManager.flush (); // når ansatt ble funnet = ansatteRepository.findByName (alex.getName ()); // deretter assertThat (found.getName ()) .isEqualTo (alex.getName ()); }

I testen ovenfor bruker vi TestEntityManager å sette inn en Ansatt i DB og lese den via find by name API.

De hevder at (…) en del kommer fra Assertj-biblioteket, som følger med Spring Boot.

5. Hånende med @MockBean

Våre Service lagkode er avhengig av vår Oppbevaringssted.

Imidlertid for å teste Service lag, trenger vi ikke å vite eller bry oss om hvordan utholdenhetslaget er implementert:

@Service offentlig klasse EmployeeServiceImpl implementerer EmployeeService {@Autowired private EmployeeRepository employeeRepository; @Override offentlig ansatt getEmployeeByName (strengnavn) {return employeeRepository.findByName (name); }}

Ideelt sett bør vi kunne skrive og teste våre Service lagkode uten ledninger i vårt fulle utholdenhetslag.

For å oppnå dette, vi kan bruke mocking-støtten som tilbys av Spring Boot Test.

La oss ta en titt på testklasseskjelettet først:

@RunWith (SpringRunner.class) offentlig klasse EmployeeServiceImplIntegrationTest {@TestConfiguration static class EmployeeServiceImplTestContextConfiguration {@Bean public EmployeeService employeeService () {return new EmployeeServiceImpl (); }} @Autowired private EmployeeService employeeService; @MockBean private EmployeeRepository ansatteRepository; // skriv prøvesaker her}

For å sjekke Service klasse, må vi ha en forekomst av Service klasse opprettet og tilgjengelig som en @Bønne slik at vi kan @Autowire det i testklassen vår. Vi kan oppnå denne konfigurasjonen ved hjelp av @TestConfiguration kommentar.

Under komponentskanning kan vi oppdage at komponenter eller konfigurasjoner som bare er opprettet for bestemte tester, ved et uhell blir hentet overalt. For å forhindre dette, Spring Boot gir @TestConfiguration kommentar som vi kan legge til på klasser i src / test / java for å indikere at de ikke skal hentes ved skanning.

En annen interessant ting her er bruken av @MockBean. Det skaper en Mock for Ansattes depot, som kan brukes til å omgå anropet til det faktiske Ansattes depot:

@Før offentlig ugyldig setUp () {Ansatt alex = ny ansatt ("alex"); Mockito.when (employeeRepository.findByName (alex.getName ())) .thenReturn (alex); }

Siden oppsettet er gjort, blir testsaken enklere:

@Test offentlig ugyldig nårValidName_thenEmployeeShouldBeFound () {String name = "alex"; Ansatt funnet = ansatteService.getEmployeeByName (navn); assertThat (found.getName ()) .isEqualTo (name); }

6. Enhetstesting med @WebMvcTest

Våre Kontroller kommer an på Service lag; la oss bare inkludere en enkelt metode for enkelhet:

@RestController @RequestMapping ("/ api") offentlig klasse EmployeeRestController {@Autowired private EmployeeService employeeService; @GetMapping ("/ ansatte") offentlig liste getAllEmployees () {return medarbeiderService.getAllEmployees (); }}

Siden vi bare fokuserer på Kontroller kode, er det naturlig å spotte Service lagkode for enhetstestene våre:

@RunWith (SpringRunner.class) @WebMvcTest (EmployeeRestController.class) offentlig klasse EmployeeRestControllerIntegrationTest {@Autowired private MockMvc mvc; @MockBean privat EmployeeService-tjeneste; // skriv testsaker her}

Å teste Kontrollere, Vi kan bruke @WebMvcTest. Den konfigurerer automatisk vår MVC-infrastruktur for enhetstestene våre.

I de fleste tilfeller, @WebMvcTest vil være begrenset til å starte en enkelt kontroller. Vi kan også bruke den sammen med @MockBean å gi mock implementeringer for alle nødvendige avhengigheter.

@WebMvcTest konfigurerer også automatisk MockMvc, som tilbyr en kraftig måte å enkelt teste MVC-kontrollere uten å starte en full HTTP-server.

Når det er sagt, la oss skrive testsaken vår:

@Test offentlig ugyldighet gittEmployees_whenGetEmployees_thenReturnJsonArray () kaster Unntak {Employee alex = new Employee ("alex"); Liste allEmployees = Arrays.asList (alex); given (service.getAllEmployees ()). willReturn (allEmployees); mvc.perform (get ("/ api / ansatte") .contentType (MediaType.APPLICATION_JSON)) .andExpect (status (). isOk ()). andExpect (jsonPath ("$", hasSize (1))). og Expect ( jsonPath ("$ [0] .name", er (alex.getName ()))); }

De få(…) metodeanrop kan erstattes av andre metoder som tilsvarer HTTP-verb som sette(), post()osv. Vær oppmerksom på at vi også angir innholdstypen i forespørselen.

MockMvc er fleksibel, og vi kan lage enhver forespørsel ved hjelp av den.

7. Integrasjonstesting med @SpringBootTest

Som navnet antyder, fokuserer integrasjonstester på å integrere forskjellige lag i applikasjonen. Det betyr også at det ikke er noen hån.

Ideelt sett bør vi holde integrasjonstestene atskilt fra enhetstestene og ikke kjøre sammen med enhetstestene. Vi kan gjøre dette ved å bruke en annen profil for bare å kjøre integrasjonstestene. Et par grunner til å gjøre dette kan være at integrasjonstestene er tidkrevende og kanskje trenger en faktisk database for å utføre.

I denne artikkelen vil vi imidlertid ikke fokusere på det, og i stedet vil vi bruke lagring av H2-persistens i minnet.

Integrasjonstestene må starte en container for å utføre testtilfellene. Derfor er det nødvendig med noe ekstra oppsett for dette - alt dette er enkelt i Spring Boot:

@RunWith (SpringRunner.class) @SpringBootTest (SpringBootTest.WebEnvironment.MOCK, classes = Application.class) @AutoConfigureMockMvc @TestPropertySource (locations = "classpath: application-integrationtest.properties") offentlig klasse EmployeeRestControllerIntegrationTtegrationMc @Autowired private EmployeeRepository repository; // skriv testsaker her}

De @SpringBootTest kommentar er nyttig når vi trenger å starte hele containeren. Merknaden fungerer ved å lage ApplicationContext som vil bli brukt i testene våre.

Vi kan bruke webMiljø attributt av @SpringBootTest å konfigurere kjøretidsmiljøet vårt; vi bruker WebEnvironment.MOCK her slik at beholderen vil fungere i et latterlig servlet-miljø.

Neste, den @TestPropertySource kommentar hjelper deg med å konfigurere stedene for eiendomsfiler som er spesifikke for testene våre. Merk at eiendomsfilen lastet med @TestPropertySource vil overstyre det eksisterende application.properties fil.

De program-integrasjonstest.egenskaper inneholder detaljene for å konfigurere utholdenhetslagring:

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

Hvis vi vil kjøre integrasjonstestene våre mot MySQL, kan vi endre verdiene ovenfor i egenskapsfilen.

Testtilfellene for integrasjonstestene kan se ut som Kontroller lagsenhetstester:

@Test offentlig ugyldig givenEmployees_whenGetEmployees_thenStatus200 () kaster Unntak {createTestEmployee ("bob"); mvc.perform (get ("/ api / ansatte") .contentType (MediaType.APPLICATION_JSON)). og Expect (status (). isOk ()). og Expect (content () .contentTypeCompatibleWith (MediaType.APPLICATION_JSON)) .andExpect (jsonPath ("$ [0] .name", er ("bob"))); }

Forskjellen fra Kontroller lagsenhetstester er at her spottes ingenting, og end-to-end-scenarier vil bli utført.

8. Autokonfigurerte tester

En av de fantastiske egenskapene til Spring Boot's automatisk konfigurerte merknader er at det hjelper å laste inn deler av hele applikasjonen og testspesifikke lag i kodebasen.

I tillegg til de ovennevnte kommentarene, er det en liste over noen få brukte kommentarer:

  • @WebFluxTest: Vi kan bruke @WebFluxTest kommentar for å teste Spring WebFlux-kontrollere. Det brukes ofte sammen med @MockBean å gi mock-implementeringer for nødvendige avhengigheter.
  • @JdbcTest: We kan bruke @JdbcTest kommentar for å teste JPA-applikasjoner, men det er for tester som bare krever en Datakilde. Kommentaren konfigurerer en innebygd database i minnet og en JdbcTemplate.
  • @JooqTest: For å teste jOOQ-relaterte tester kan vi bruke @JooqTest kommentar, som konfigurerer en DSLContext.
  • @DataMongoTest: For å teste MongoDB-applikasjoner, @DataMongoTest er en nyttig kommentar. Som standard konfigurerer den en innebygd MongoDB i minnet hvis driveren er tilgjengelig gjennom avhengigheter, konfigurerer en MongoTemplate, skanner etter @Dokument klasser, og konfigurerer Spring Data MongoDB-arkiver.
  • @DataRedisTestgjør det lettere å teste Redis-applikasjoner. Den skanner etter @RedisHash klasser og konfigurerer Spring Data Redis-arkiver som standard.
  • @DataLdapTest konfigurerer et innebygd minne LDAP (hvis tilgjengelig), konfigurerer a LdapTemplate, skanner etter @Inngang klasser, og konfigurerer vårdata LDAP repositories som standard.
  • @RestClientTest: Vi bruker vanligvis @RestClientTest kommentar for å teste REST-klienter. Den konfigurerer automatisk forskjellige avhengigheter som støtte for Jackson, GSON og Jsonb; konfigurerer en RestTemplateBuilder; og legger til støtte for MockRestServiceServer som standard.

9. Konklusjon

I denne artikkelen tok vi et dypdykk i teststøtten i Spring Boot og viste hvordan vi kan skrive enhetstester effektivt.

Den komplette kildekoden til denne artikkelen finner du på GitHub. Kildekoden inneholder mange flere eksempler og forskjellige testtilfeller.

Og hvis du vil fortsette å lære om testing, har vi separate artikler relatert til integrasjonstester og enhetstester i JUnit 5.


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