[JAVA] Test unitaire de l'API Web et test d'intégration avec SpringBoot + Junit5, 4 modèles

Test unitaire de l'API Web et test d'intégration

Lors de la création d'une nouvelle API Web avec PJ, j'ai vérifié quel type de test peut être créé avec Junit, alors prenez note.

table des matières

Code de test

  1. [Test unitaire (test par classe)](# 1 Test unitaire Test par classe)
  2. [Test d'intégration 1 (intégration de plusieurs classes)](# 2 test d'intégration 1 intégration de plusieurs classes)
  3. [Test d'intégration 2 (Intégration de toutes les classes, environnement local)](# 3 Test d'intégration 2 Intégration de toutes les classes, environnement local)
  4. [Test d'intégration 3 (Intégration de toutes les classes, environnement arbitraire)](# 4 Test d'intégration 3 Intégration de toutes les classes, environnement arbitraire)

Code à tester

1. Test unitaire (test par classe)

Insérez une maquette avec mockito sans dépendre des autres classes. Le test est possible sans attendre l'implémentation d'autres classes.

EmployeeControllerSliceTest


import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import com.example.demo.domain.Employee;
import com.example.demo.usecase.GetEmployeeUsecase;
@WebMvcTest(EmployeeController.class)
class EmployeeControllerSliceTest {
    /**Mock pour injecter dans la cible de test*/
    @MockBean
    GetEmployeeUsecase mockedUsecase;
    /**Client pour le test de connexion*/
    @Autowired
    private MockMvc mvc;
    @Test
    void testGetOne() throws Exception {
        //Définir un mouvement simulé
        when(this.mockedUsecase.getEmployee(anyString())).thenReturn(Optional.ofNullable(new Employee("foo", "bar")));
        //Lancer le test
        this.mvc.perform(get("/employees/{employeeId}", "123")) //
        .andExpect(status().is(200)) //
        .andExpect(content().json("{\"employeeId\":\"foo\",\"name\":\"bar\"}")); //Mock data indépendamment de la requête
    }
}

référence Auto-configured Spring MVC Tests Mocking and Spying Beans

2. Test d'intégration 1 (intégration de plusieurs classes)

Peut être testé en déclarant explicitement la dépendance à d'autres classes.

EmployeeControllerSliceAndImportTest


package com.example.demo.presentation;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;
import com.example.demo.infrastructure.TempEmployeeRepositoryImp;
import com.example.demo.usecase.GetEmployeeUsecase;
@WebMvcTest(EmployeeController.class)
@Import({ GetEmployeeUsecase.class, TempEmployeeRepositoryImp.class })
class EmployeeControllerSliceAndImportTest {
    /**Client pour le test de connexion*/
    @Autowired
    private MockMvc mvc;
    @Test
    void testGetOne() throws Exception {
        //Courir
        this.mvc.perform(get("/employees/{employeeId}", "123")) //
        //Vérification
        .andExpect(status().is(200)) //
        .andExpect(content().json("{\"employeeId\":\"123\",\"name\":\"Taro\"}")); //Données obtenues à partir du référentiel
    }
}

référence Auto-configured Spring MVC Tests

3. Test d'intégration 2 (intégration de toutes les classes, environnement local)

Le test local est possible dans un environnement qui est presque le même que lorsque le serveur réel est démarré.

EmployeeControllerOnLocalhostTest


package com.example.demo.presentation;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.reactive.server.WebTestClient;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class EmployeeControllerOnLocalhostTest {
    /**Client pour le test de connexion*/
    WebTestClient client = WebTestClient.bindToServer().build();
    /**Numéro de port de destination de la connexion*/
    @LocalServerPort
    private int port;
    @Test
    void test() throws Exception {
        //Courir
        this.client.get().uri("http://localhost:" + this.port + "/employees/{employeeId}", "123").exchange() //
        //Vérification
        .expectStatus().isEqualTo(HttpStatus.valueOf(200)) //
        .expectBody(String.class).isEqualTo("{\"employeeId\":\"123\",\"name\":\"Taro\"}");
    }
}

référence Testing with a running server WebTestClient Spring WebClient Requests with Parameters

4. Test d'intégration 3 (intégration de toutes les classes, de tout environnement)

Vous pouvez vous connecter à n'importe quel serveur en cours d'exécution et tester son comportement. Il est nécessaire de démarrer le serveur séparément avant d'exécuter le test Junit. Inversement, vous pouvez tester n'importe quel serveur d'API Web en cours d'exécution. Il n'est pas nécessaire que ce soit Java.

EmployeeControllerOnExternalServerTest


package com.example.demo.presentation;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.test.web.reactive.server.WebTestClient;
class EmployeeControllerOnExternalServerTest {
    /**Client pour le test de connexion*/
    WebTestClient client = WebTestClient.bindToServer().build();
    /**Numéro de port de destination de la connexion*/
    private final int port = 8080;
    @Test
    void test() throws Exception {
        //Courir
        this.client.get().uri("http://localhost:" + this.port + "/employees/{employeeId}", "123").exchange() //
        //Vérification
        .expectStatus().isEqualTo(HttpStatus.valueOf(200)) //
        .expectBody(String.class).isEqualTo("{\"employeeId\":\"123\",\"name\":\"Taro\"}");
    }
}

référence WebTestClient Spring WebClient Requests with Parameters

Code à tester

EmployeeController.java

EmployeeController


package com.example.demo.presentation;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.domain.Employee;
import com.example.demo.usecase.GetEmployeeUsecase;
@RestController
public class EmployeeController {
    @Autowired
    GetEmployeeUsecase getUsecase;
    @GetMapping("/employees/{employeeId}")
    Optional<Employee> getOne(@PathVariable final String employeeId) {
        return this.getUsecase.getEmployee(employeeId);
    }
}

GetEmployeeUsecase.java

GetEmployeeUsecase


package com.example.demo.usecase;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.domain.Employee;
import com.example.demo.domain.EmployeeRepository;
@Service
public class GetEmployeeUsecase {
    @Autowired
    EmployeeRepository repository;
    public Optional<Employee> getEmployee(final String employeeId) {
        return this.repository.findOneById(employeeId);
    }
}

Employee.java

Employee


package com.example.demo.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Employee {
    private String employeeId = null;
    private String name = null;
    @SuppressWarnings("unused")
    private Employee() {
    }
}

EmployeeRepository.java

EmployeeRepository


package com.example.demo.domain;
import java.util.Optional;
import org.springframework.stereotype.Repository;
public interface EmployeeRepository {
    Optional<Employee> findOneById(String employeeId);
}

TempEmployeeRepositoryImp.java

TempEmployeeRepositoryImp


package com.example.demo.infrastructure;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Repository;
import com.example.demo.domain.Employee;
import com.example.demo.domain.EmployeeRepository;
@Repository
public class TempEmployeeRepositoryImp implements EmployeeRepository {
    private final List<Employee> db;
    public TempEmployeeRepositoryImp() {
        this.db = new ArrayList<>();
        //Comme données initiales
        this.db.add(new Employee("123", "Taro"));
    }
    @Override
    public Optional<Employee> findOneById(final String employeeId) {
        return this.db.stream().filter(e -> e.getEmployeeId().equals(employeeId)).findFirst();
    }
}

GitHub https://github.com/tmtmra/restControllerTestSample

finalement

Je suis un débutant qui a commencé à programmer il y a un an, alors n'hésitez pas à me donner divers avis et conseils.

Recommended Posts

Test unitaire de l'API Web et test d'intégration avec SpringBoot + Junit5, 4 modèles
Faites un test unitaire avec Junit.
Mélanger les cas de test avec JUnit 5 et les méthodes par défaut
Test d'intégration avec Gradle
Tester l'API Web avec junit
[Java] Tester des méthodes privées avec JUnit
Copier et coller le test avec RSpec
Contrôleur de cadre de test Spring avec Junit
[rails] Faisons un test unitaire avec Rspec!
Introduire RSpec et écrire le code de test unitaire
Contrôler l'ordre de test dans Junit4 avec un type d'énumération
Comment tester l'étendue privée avec JUnit
Le test JUnit 5 Gradle génère une erreur avec l'annotation Lombok
Présentation du test Java automatisé avec JUnit 5 + Gradle
[Java] Comment tester s'il est nul dans JUnit
À propos de la conception de Spring Boot et de l'environnement de test unitaire
[CircleCI 2.0] [Java] [Maven] [JUnit] Agréger les résultats des tests JUnit avec CircleCI 2.0
Présentation des tests Java automatisés avec JUnit 5 + Apache Maven
Comment tester les interruptions pendant Thread.sleep avec JUnit
Créez et testez des applications Java + Gradle avec Wercker
Test JUnit facile de la version Elasticsearch 2018 avec Embedded-elasticsearch
Écraser le contenu de la configuration avec Spring-boot + JUnit5
Tester le code à l'aide d'une maquette avec JUnit (centre EasyMock)
Faites un test unitaire avec Junit.
Test unitaire de l'API Web et test d'intégration avec SpringBoot + Junit5, 4 modèles
Introduire RSpec et écrire le code de test unitaire
Contrôler l'ordre de test dans Junit4 avec un type d'énumération
À propos de la conception de Spring Boot et de l'environnement de test unitaire
Mélanger les cas de test avec JUnit 5 et les méthodes par défaut
Lancement du test JUnit essayez quelque chose
Échantillon de bibliothèque de tests unitaires Java
Utilisez Spring Test + Mockito + JUnit 4 pour le test unitaire Spring Boot + Spring Retry