Sådan tester du tjenester, slutpunkter og opbevaringssteder i Spring Boot

I dette indlæg vil jeg vise dig, hvordan du skriver enhedstest i foråret boot applikationer.

Hvorfor er det nødvendigt at skrive enhedstest kræver en anden artikel at forklare. Men for en kort forklaring vil jeg fortælle dig flere ting.

Jeg forsvarer normalt argumentet om, at kode uden enhedstest er død kode. Fordi når en udvikler tilføjer en ny funktion til en kode, der ikke er dækket af en enhedstest, er den tilbøjelig til at tilsidesætte eksisterende forretningsregler (som dræber den kode, der er skrevet før). Måske er det ikke ligefrem tilbøjeligt til det, men du kan forestille dig, hvilke fejl der kan opstå, når et komplekst projekt skal ændres. Enhedstest er den eneste måde at beskytte din kode mod at bryde ændringer.

Hvorfor enhedstest slutpunkter?

Hver gang vi skriver et slutpunkt, skal vi være sikre på, at flere ting fungerer korrekt. Slutpunktet skal returnere dataene i den korrekte struktur og håndtere anmodningen korrekt. Vi kan teste det manuelt, hvilket ikke er at foretrække. Så vi skriver enhedstest for at sikre, at vores slutpunkter fungerer korrekt. Der er også en anden måde at teste slutpunkter på, kendt som automatiseringstest, men det er ikke emnet for dette indlæg.

Hvorfor enhedstesttjenester?

Det skal allerede være klart, men bare i tilfælde: vi skal være sikre på, at vores forretningslogik fungerer korrekt.

Hvorfor enhedstestopbevaringssteder?

Der er flere tilfælde for at teste opbevaringssteder. Selvfølgelig tester vi ikke selve rammen. Men vi skriver enhedstest for at være sikre på, at vores specifikationer eller forhold er implementeret korrekt.

Så hvordan tester vi controllere?

Nu er det tid til at vise dig, hvordan du tester vores controllere i forårsstøvlen. Lad os forestille os, at vi skriver en applikation, der giver os mulighed for at gemme brugere i en database. Vi definerer en brugerenhed, en brugertjeneste og en controller.

Bemærk: Eksemplerne vist i dette indlæg er ikke til ægte arkitektur til produktionsbrug

@[email protected] class User { @Id @GeneratedValue(generator = "uuid2") @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator") @Column(name = "id", columnDefinition = "BINARY(16)") private UUID id; private String name; private String email; private int age;}
@Datapublic class CreateUserRequest { private String name; private String email; private int age;}
@[email protected]("/users")public class UserController { UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } @PostMapping public ResponseEntity createUser(@RequestBody CreateUserRequest request) { User created = userService.save(request); return ResponseEntity.ok(created); }}

Vores controller er afhængig af UserService, men vi er ikke interesserede i, hvad service gør lige nu.

Så lad os nu skrive en enhedstest til vores controller for at være sikker på, at den fungerer korrekt.

Vi hånede vores service, fordi vi ikke har brug for dens implementeringsoplysninger. Vi tester bare vores controller her. Vi bruger MockMvcher til at teste vores controller og objektmapper til serialiseringsformål.

Vi konfigurerer vores userService.Save() metode til at returnere det ønskede brugerobjekt. Vi passerede en anmodning til vores controller, og efter at vi kontrollerede de returnerede data med følgende linje: andExpect(jsonPath("$.name").value(request.getName())).

Vi har også andre metoder at bruge. Her er listen over metoder:

Når vi kører testen, ser vi, at den består.

Hvordan tester vi tjenester?

Nu går vi for at teste vores UserService. Det er ret simpelt at teste.

Vi håner lageret og injicerer vores mocks i UserService. Nu når vi kører testen, ser vi, at den består.

Lad os nu tilføje en forretningsregel til UserService: Lad os sige, at brugeren skal have en e-mail-adresse.

Vi ændrer vores gemningsmetode i UserService som nedenfor:

public User save(CreateUserRequest request) { requireNonNull(request.getEmail()); User user = new User(); user.setName(request.getName()); user.setEmail(request.getEmail()); user.setAge(request.getAge()); userRepository.save(user); return user;}

Når vi kører testen igen, ser vi en mislykket test.

Før vi ordner det, lad os skrive en test, der tilfredsstiller denne forretning.

Vi skrev en ny test, der specificerede, at hvis vi sender en null-e-mail, smider den NullPointerException.

Lad os rette den mislykkede test ved at tilføje en e-mail til vores anmodning:

createUserRequest.setEmail("testemail");

Kør begge tests:

Hvordan tester vi arkiver?

Nu er vi kommet til at teste opbevaringssteder. Vi bruger en hukommelse i h2-database medTestEntityManager.

Vores lager er defineret som nedenfor:

@Repositorypublic interface UserRepository extends JpaRepository, JpaSpecificationExecutor { Optional findById(UUID id);}

Konfigurer først h2db. Opret filnavnet application.yaml i test -> ressourcesti:

spring: application: name: Spring Boot Rest API datasource: type: com.zaxxer.hikari.HikariDataSource url: "jdbc:h2:mem:test-api;INIT=CREATE SCHEMA IF NOT EXISTS dbo\\;CREATE SCHEMA IF NOT EXISTS definitions;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;MODE=MSSQLServer" name: password: username: initialization-mode: never hikari: schema: dbo jpa: database: H2 database-platform: org.hibernate.dialect.H2Dialect show-sql: true hibernate: ddl-auto: create-drop test: database: replace: none

Og lad os først skrive en grundlæggende test til vores lager: Gem en bruger og hent den:

@RunWith(SpringRunner.class)@DataJpaTestpublic class UserRepositoryTest { @Autowired TestEntityManager entityManager; @Autowired UserRepository sut; @Test public void it_should_save_user() { User user = new User(); user.setName("test user"); user = entityManager.persistAndFlush(user); assertThat(sut.findById(user.getId()).get()).isEqualTo(user); }}

Når vi kører det, ser vi en masse konsoloutput, og også vores test består:

Lad os nu tilføje en anden metode til vores arkiv til søgning efter en bruger via e-mail:

Optional findByEmail(String email);

Og skriv endnu en test:

@Testpublic void it_should_find_user_byEmail() { User user = new User(); user.setEmail("[email protected]"); user = entityManager.persistAndFlush(user); assertThat(sut.findByEmail(user.getEmail()).get()).isEqualTo(user);}

Når vi kigger på konsollen efter at have kørt testen, ser vi SQL genereret af dvale:

SELECT user0_.id AS id1_1_,user0_.age AS age2_1_,user0_.email AS email3_1_,user0_.name AS name4_1_FROM user user0_WHERE user0_.email=?

Så langt så godt. Vi har dækket det grundlæggende om enhedstest med fjederstøvle.

Nu har du ingen undskyldninger for ikke at skrive enhedstest! Jeg håber, det er klart for dig, hvordan du skriver enhedstest til forskellige slags formål.