[JAVA] J'ai écrit un test avec Spring Boot + JUnit 5 maintenant

introduction

Quand je me suis trop habitué à JUnit4 et que j'ai décidé d'écrire en JUnit5, j'ai dû enquêter un peu. Maintenant, je vais résumer moi-même les exemples d'implémentation fréquemment utilisés.

L'application Web à tester suppose l'API Rest et n'inclut pas le test de couche View.

Exemple d'implémentation couvert dans cet article

Environnement de développement

1. Préparation de l'application à tester

Tout d'abord, créez une application à tester. Comme d'habitude, Créé en ajoutant lombok, Spring Web et Validation à GradleProject avec spring initializr .RELEASE & packaging = jar & jvmVersion = 11 & groupId = com.example & artifactId = demo & name = demo & description = Demo% 20project% 20for% 20Spring% 20Boot & packageName = com.example.demo & dependencies = lombok, web, validation).

build.gradle


plugins {
	id 'org.springframework.boot' version '2.3.4.RELEASE'
	id 'io.spring.dependency-management' version '1.0.10.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
	testCompileOnly 'org.projectlombok:lombok'  //ajouter à
	testAnnotationProcessor 'org.projectlombok:lombok'  //ajouter à
}

test {
	useJUnitPlatform()
}

Pour le build.gradle généré, deux lignes ont été ajoutées à dependency afin que lombok puisse être utilisé dans le code de test. (Voir les commentaires ci-dessus) Nous allons créer les classes suivantes pour ce projet.

1-1. Création du service et de la configuration

Créez deux Services appelés depuis Controller. Tout d'abord, il effectue un traitement interne simple.

DemoService.java


@Service
public class DemoService {
  //Je te saluerai
  public String hello() {
    return "hello";
  }
  //Je diviserai
  public BigDecimal divide(BigDecimal a, BigDecimal b) {
    return a.divide(b, 2, RoundingMode.HALF_UP);
  }
}

L'autre consiste à acquérir une ressource externe (API Qiita).

ExternalService.java


@Service
@RequiredArgsConstructor
public class ExternalService {
  private static final String EXTERNAL_RESOURCE_URL = "https://qiita.com/api/v2/schema";
  private final RestTemplate restTemplate;
  //Renvoie le résultat du schéma de l'API Qiita
  public String getExternalResource() {
    ResponseEntity<String> response =
        restTemplate.exchange(EXTERNAL_RESOURCE_URL, HttpMethod.GET, null, String.class);
    return response.getBody();
  }
}

Créez une classe Configuration pour DI le restTemplate ci-dessus.

AppConfig.java


@Configuration
public class AppConfig {
  @Bean
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }
}

1-2. Création d'un contrôleur

Créez un contrôleur qui utilise les deux services mentionnés précédemment.

DemoController.java


@RestController
@RequiredArgsConstructor
@Validated
public class DemoController {

  private final DemoService demoService;
  private final ExternalService externalService;

  //Je te saluerai
  @GetMapping("/")
  public CommonResponse hello() {
    String data = demoService.hello();
    return CommonResponse.builder().data(data).build();
  }

  //Je diviserai
  @GetMapping("/divide/{num1}/{num2}")
  public CommonResponse divide(
      @PathVariable @Pattern(regexp = "[0-9]*") String num1,
      @PathVariable @Pattern(regexp = "[0-9]*") String num2) {
    BigDecimal data = demoService.divide(new BigDecimal(num1), new BigDecimal(num2));
    return CommonResponse.builder().data(data).build();
  }

  //Renvoie le résultat du schéma de l'API Qiita
  @GetMapping("/external")
  public CommonResponse external() {
    String data = externalService.getExternalResource();
    return CommonResponse.builder().data(data).build();
  }
}

Puisque la division vérifie l'entrée, nous mettrons en œuvre le cas de test plus tard de ce point de vue. Créez la classe de réponse comme suit.

CommonResponse.java


@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CommonResponse<T> {
    @Builder.Default
    private String status = "success";
    @Builder.Default
    private String message = "request succeeded.";
    private T data;
}

1-3. Création de Filter et ExceptionHandler

Nous allons également créer un filtre et un ExceptionHandler pour un exemple plus pratique. Ce filtre est aussi simple que la sortie d'un journal avant et après le traitement d'une demande.

LogFilter.java


@Component
@Slf4j
public class LogFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    log.info("[IN]{}:{}", req.getMethod(), req.getRequestURI());
    try {
      chain.doFilter(request, response);
    } finally {
      log.info("[OUT]{}:{}", req.getMethod(), req.getRequestURI());
    }
  }
}

Créez également un ExceptionHandler. Il est utilisé pour gérer diverses erreurs communes.

CommonExceptionHandler.java


@RestControllerAdvice
@Slf4j
public class CommonExceptionHandler extends ResponseEntityExceptionHandler {

  // 404:Gère les erreurs de ressource introuvable
  //* Pour gérer cette application.Vous devez également définir des propriétés
  @Override
  protected ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    ServletWebRequest req = (ServletWebRequest)request;
    log.warn("resource not found. {}", req.getRequest().getRequestURI());
    return new ResponseEntity(
            CommonResponse.builder().status("failure").message("resource not found.").build(),
            HttpStatus.NOT_FOUND);
  }

  // 400:Gère les erreurs de vérification d'entrée
  @ExceptionHandler(ConstraintViolationException.class)
  public ResponseEntity<CommonResponse> handleValidationError(ConstraintViolationException e) {
    //Séparez les éléments d'erreur d'entrée et les messages par des virgules(,)Ajouté à.
    String validationErrorMessages =
        e.getConstraintViolations().stream()
            .map(cv -> cv.getPropertyPath().toString() + ":" + cv.getMessage())
            .collect(Collectors.joining(", "));
    log.info("Bad request. {}", validationErrorMessages);
    return new ResponseEntity<>(
        CommonResponse.builder().status("failure").message(validationErrorMessages).build(),
        HttpStatus.BAD_REQUEST);
  }

  // 500:Je vais gérer d'autres erreurs inconnues
  @ExceptionHandler
  public ResponseEntity<CommonResponse> handleException(Exception e) {
    log.error("Request failed.", e);
    return new ResponseEntity<>(
        CommonResponse.builder().status("failure").message("error has occurred.").build(),
        HttpStatus.INTERNAL_SERVER_ERROR);
  }
}

Placez les paramètres suivants dans ʻapplication.properties pour gérer 404: Resouce Not Found` dans le ExceptionHandler ci-dessus.

application.properties


spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

1-4. Structure du fichier créé

Ceci termine la préparation de l'application à utiliser pour les tests. Les fichiers édités et créés jusqu'à présent ont la structure suivante.

├── build.gradle
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com.example.demo
│   │   │               ├── AppConfig.java
│   │   │               ├── DemoApplication.java
│   │   │               ├── controller
│   │   │               │   ├── CommonExceptionHandler.java
│   │   │               │   ├── CommonResponse.java
│   │   │               │   └── DemoController.java
│   │   │               ├── filter
│   │   │               │   └── LogFilter.java
│   │   │               └── service
│   │   │                   ├── DemoService.java
│   │   │                   └── ExternalService.java
│   │   └── resources
│   │       └── application.properties
│   └── test
└── web

2. Test du contrôleur

Les principaux rôles du contrôleur sont les suivants.

--Mappage de demande --Obtenir des paramètres

Étant donné que ces comportements dépendent de la fonctionnalité de Spring MVC, il n'a pas beaucoup de sens d'écrire du code de test pour la classe Controller uniquement. Par conséquent, nous utiliserons MockMVC pour effectuer un test qui reproduit le comportement de Spring MVC.

2-1. Exemple de scénario de test utilisant MockMVC

En ce qui concerne la demande acceptée par le contrôleur, non seulement le cas normal mais également la réponse du cas anormal supposé tel qu'une erreur de vérification d'entrée est vérifiée sans exception.

DemoControllerTest.java


package com.example.demo.controller;

import com.example.demo.filter.LogFilter;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@EnableWebMvc
@Slf4j
public class DemoControllerTest {

  MockMvc mockMvc;

  @Autowired WebApplicationContext webApplicationContext;
  @Autowired LogFilter logFilter;

  @BeforeEach
  void beforeEach() {
    mockMvc =
        MockMvcBuilders.webAppContextSetup(webApplicationContext)     //Configurer Mock MVC
            .addFilter(logFilter, "/*")                               //Cependant, le filtre doit être ajouté manuellement
            .build();
  }

  //racine"/Je vais tester votre demande
  @Test
  void hello() throws Exception {
    mockMvc.perform(get("/"))                                         //racine"/Envoyez une pseudo requête à
        .andExpect(status().isOk())                                   //HttpStatus est égal à 200:Être d'accord
        .andExpect(jsonPath("$.status").value("success"))             //La valeur de json est comme prévu
        .andExpect(jsonPath("$.message").value("request succeeded.")) // 〃
        .andExpect(jsonPath("$.data").value("hello"));
  }

  //Je vais tester la demande de division (10/3)
  @Test
  void divideSuccess() throws Exception { 
    mockMvc
        .perform(get("/divide/10/3"))                                 // 「/divide/10/Envoyer une pseudo requête à 3 "
        .andExpect(status().isOk())                                   //HttpStatus est égal à 200:Être d'accord
        .andExpect(jsonPath("$.status").value("success"))
        .andExpect(jsonPath("$.message").value("request succeeded."))
        .andExpect(jsonPath("$.data").value("3.33"));                 // 10 ÷ 3 = 3.Être 33
  }
  
  //Test des mauvaises requêtes (10 ÷ aaa)
  @Test
  void divideInvalidParameter() throws Exception {
    mockMvc
        .perform(get("/divide/10/aaa"))                               // 「/divide/10/Envoyer une pseudo requête à "aaa"
        .andExpect(status().isBadRequest())                           //HttpStatus est 400:Être une mauvaise demande
        .andExpect(jsonPath("$.status").value("failure"))
        .andExpect(jsonPath("$.message").value("divide.num2:must match \"[0-9]*\"")); //Il y a un message d'erreur
  }

  //Je vais tester une demande de division zéro (10 ÷ 0)
  @Test
  void divideZeroError() throws Exception {
    mockMvc
        .perform(get("/divide/10/0"))                                   // 「/divide/10/Envoyer une pseudo requête à "0"
        .andExpect(status().is5xxServerError())                         //HttpStatus est 500:ServerError
        .andExpect(jsonPath("$.status").value("failure"))
        .andExpect(jsonPath("$.message").value("error has occurred."));
  }
  
  //Tester l'acquisition de ressources externes (API de schéma Qiita)
  @Test
  void getExternalResource() throws Exception {
    MvcResult mvcResult =
        mockMvc
            .perform(get("/external"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.status").value("success"))
            .andExpect(jsonPath("$.message").value("request succeeded."))
            .andExpect(jsonPath("$.data").isNotEmpty())                //Pas vide
            .andReturn();
    //Je vais afficher la réponse acquise dans le journal
    log.info("external response : {}", mvcResult.getResponse().getContentAsString());
  }
}

Le but est de configurer MockMvc avec WebAppicationContext. [^ 1] En faisant cela, vous pouvez reproduire l'état qui est presque le même que le déploiement sur le serveur d'applications.

[^ 1]: MockMvc a également une autre configuration autonome, et il existe également un mode approprié pour les tests unitaires qui peuvent être finement personnalisés tels que Controller, ControllerAdvice, Config à tester.

** Cependant, notez que vous devez spécifier uniquement Filter avec ʻaddFilter (Filter," path ")` par vous-même. ** **

3. Test avec Mock

Le test précédent utilisait le contrôleur DI et le service.

Cependant, lors de l'utilisation d'une ressource externe telle que ʻExternalService`, il n'est pas bon que le test du contrôleur échoue en raison de l'état (l'autre serveur est arrêté et inaccessible, le Wi-Fi est désactivé, etc.). ..

** Utilisez Mock à de tels moments. ** **

3-1. Mock le haricot et le tester

Si vous vérifiez à nouveau le rôle de contrôleur,

  1. Demande de cartographie
  2. Obtenir les paramètres
  3. Vérification d'entrée
  4. Appel de la logique métier (service)
  5. Retour de la réponse

Cependant, parmi ceux-ci, «4. Calling Business Logic (Service)» peut être ** simulé pour renvoyer la valeur attendue afin que vous puissiez vous concentrer sur le test du contrôleur **.

Convertissons la classe Service du test précédent en Mock.

DemoControllerWithMockTest.java


package com.example.demo.controller;

import com.example.demo.filter.LogFilter;
import com.example.demo.service.DemoService;
import com.example.demo.service.ExternalService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import java.math.BigDecimal;

import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@EnableWebMvc
@Slf4j
class DemoControllerWithMockTest {

  MockMvc mockMvc;

  @Autowired WebApplicationContext webApplicationContext;
  @Autowired LogFilter logFilter;

  @MockBean DemoService demoService;         //Convertir en maquette et enregistrer dans un conteneur DI
  @MockBean ExternalService externalService; // 〃

  @BeforeEach
  void beforeEach() {
    MockitoAnnotations.initMocks(this);
    mockMvc =
        MockMvcBuilders.webAppContextSetup(webApplicationContext)
            .addFilter(logFilter, "/*")
            .build();
  }

  @AfterEach
  void afterEach() {}

  @Test
  void hello() throws Exception {
    // mock
    when(demoService.hello()).thenReturn("Bonjour");      //Définissez d'abord la valeur de retour de la maquette
    // request execute
    mockMvc
        .perform(get("/"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.status").value("success"))
        .andExpect(jsonPath("$.message").value("request succeeded."))
        .andExpect(jsonPath("$.data").value("Bonjour"));  //Vérifiez en modifiant la valeur attendue
    // verify
    verify(demoService, times(1)).hello();                 //Vérifiez le nombre d'appels simulés
  }

  @Test
  void divideSuccess() throws Exception {
    // mock
    when(demoService.divide(any(), any())).thenReturn(new BigDecimal("3.33")); //Indépendamment de l'argument"3.33"rends le
    // request execute
    mockMvc
        .perform(get("/divide/10/3"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.status").value("success"))
        .andExpect(jsonPath("$.message").value("request succeeded."))
        .andExpect(jsonPath("$.data").value("3.33"));
    // verify
    verify(demoService, times(1)).divide(any(), any());
  }

  @Test
  void divideInvalidParameter() throws Exception {
    // request execute
    mockMvc
        .perform(get("/divide/10/aaa"))
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.status").value("failure"))
        .andExpect(jsonPath("$.message").value("divide.num2:must match \"[0-9]*\""));
    // verify
    verify(demoService, times(0)).divide(any(), any());  //Appel simulé validé 0 fois en raison d'une erreur d'entrée
  }

  @Test
  void divideZeroError() throws Exception {
    // mock
    when(demoService.divide(any(), eq(BigDecimal.ZERO)))
        .thenThrow(new ArithmeticException("/ by zero"));              //Reproduisez l'erreur en supposant une division nulle
    // request execute
    mockMvc
        .perform(get("/divide/10/0"))
        .andExpect(status().is5xxServerError())
        .andExpect(jsonPath("$.status").value("failure"))
        .andExpect(jsonPath("$.message").value("error has occurred."));
    // verify
    verify(demoService, times(1)).divide(any(), eq(BigDecimal.ZERO));  //L'appel simulé valide une fois
  }

  @Test
  void getExternalResource() throws Exception {
    // mock
    when(externalService.getExternalResource())
        .thenReturn("this is mock data for internal test.");    //Renvoyer le libellé sans accéder aux ressources externes
    // request execute
    MvcResult mvcResult =
        mockMvc
            .perform(get("/external"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.status").value("success"))
            .andExpect(jsonPath("$.message").value("request succeeded."))
            .andExpect(jsonPath("$.data").value("this is mock data for internal test."))
            .andReturn();
    //Je vais afficher la réponse acquise dans le journal
    log.info("external response : {}", mvcResult.getResponse().getContentAsString());
    // verify
    verify(externalService, times(1)).getExternalResource();  //L'appel simulé valide une fois
  }
}

Le plus important avec ce changement est que ʻExternalService` renvoie désormais des données factices sans accéder aux ressources externes.

Vous pouvez désormais exécuter des tests Controller indépendamment des ressources externes.

3-2. Tester l'un avec DI et l'autre avec Mock

Dans le test précédent, DemoService et ʻExternalService ont été Mocked, mais ** un seul peut être Mocked **. Par exemple, si vous souhaitez simuler uniquement ʻExternalService, ce sera comme suit.

DemoControllerWithOneSideMockTest.java


package com.example.demo.controller;

import com.example.demo.filter.LogFilter;
import com.example.demo.service.ExternalService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@EnableWebMvc
@Slf4j
class DemoControllerWithOneSideMockTest {

  MockMvc mockMvc;

  @Autowired WebApplicationContext webApplicationContext;
  @Autowired LogFilter logFilter;

  @MockBean ExternalService externalService;    //Le service externe a un accès externe, alors faites-le simuler

  @BeforeEach
  void beforeEach() {
    MockitoAnnotations.initMocks(this);
    mockMvc =
        MockMvcBuilders.webAppContextSetup(webApplicationContext)
            .addFilter(logFilter, "/*")
            .build();
  }

  @AfterEach
  void afterEach() {}

  @Test
  void hello() throws Exception {
    mockMvc
        .perform(get("/"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.status").value("success"))
        .andExpect(jsonPath("$.message").value("request succeeded."))
        .andExpect(jsonPath("$.data").value("hello"));
  }

  @Test
  void divideSuccess() throws Exception {
    mockMvc
        .perform(get("/divide/10/3"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.status").value("success"))
        .andExpect(jsonPath("$.message").value("request succeeded."))
        .andExpect(jsonPath("$.data").value("3.33"));
  }

  @Test
  void divideInvalidParameter() throws Exception {
    mockMvc
        .perform(get("/divide/10/aaa"))
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.status").value("failure"))
        .andExpect(jsonPath("$.message").value("divide.num2:must match \"[0-9]*\""));
  }

  @Test
  void divideZeroError() throws Exception {
    mockMvc
        .perform(get("/divide/10/0"))
        .andExpect(status().is5xxServerError())
        .andExpect(jsonPath("$.status").value("failure"))
        .andExpect(jsonPath("$.message").value("error has occurred."));
  }

  //Seule l'acquisition de ressources externes est vérifiée à l'aide de Mock.
  @Test
  void getExternalResource() throws Exception {
    // mock
    when(externalService.getExternalResource()).thenReturn("this is mock data for internal test.");
    // request
    MvcResult mvcResult =
        mockMvc
            .perform(get("/external"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.status").value("success"))
            .andExpect(jsonPath("$.message").value("request succeeded."))
            .andExpect(jsonPath("$.data").value("this is mock data for internal test."))
            .andReturn();
    //
    log.info("external response : {}", mvcResult.getResponse().getContentAsString());
    // verify
    verify(externalService, times(1)).getExternalResource();
  }
}

Avec cela, vous pouvez librement DI le bean au moment du test ou en faire un Mock. Très pratique! !!

4. Test de paramétrage

Enfin, je laisserai un exemple de la fonction pratique «test de paramétrage» ajoutée dans JUnit5 en utilisant le test unitaire de «Service» comme exemple. Il sera facile de répéter le même cas en ne modifiant que les données de test.

DemoServiceTest.java


package com.example.demo.service;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest
class DemoServiceTest {

  @Autowired DemoService demoService;

  @Test
  void hello() {
    assertEquals("hello", demoService.hello());
  }

  // @Je vais tester la méthode de division avec divers modèles d'entrée avec ParameterizedTest
  @ParameterizedTest
  @MethodSource("divideTestArgs")  // "devideTestArgs"J'utiliserai une méthode statique nommée
  void divide(String b1, String b2, String strExpect, boolean hasError) {

    BigDecimal expect = Optional.ofNullable(strExpect).map(BigDecimal::new).orElse(null);
    BigDecimal actual = null;
    Exception error = null;
    //Exécution de la méthode d'exécution
    try {
      actual = demoService.divide(new BigDecimal(b1), new BigDecimal(b2));
    } catch (Exception e) {
      error = e;
    }
    //Valeur attendue et vérification
    assertEquals(expect, actual);
    //Vérifiez qu'aucune erreur ne s'est produite
    assertEquals(hasError, error != null);
  }

  //diviser la liste des paramètres de test
  static List<Object[]> divideTestArgs() {
    return List.of(
        new Object[] {"1", "1", "1.00", false},
        new Object[] {"0", "1", "0.00", false},
        new Object[] {"5", "2", "2.50", false},
        new Object[] {"10", "3", "3.33", false}, //Arrondi (arrondi au troisième chiffre de la virgule décimale)
        new Object[] {"11", "3", "3.67", false}, //Arrondi (arrondi au troisième chiffre de la virgule décimale)
        new Object[] {"1", "0", null, true}); //Diviser à zéro
  }
}

En outre, MethodSource

Il semble que vous puissiez l'utiliser comme source de données.

À propos de la fonction de JUnit5 [cette page](https://qiita.com/opengl-8080/items/efe54204e25f615e322f#%E3%83%91%E3%83%A9%E3%83%A1%E3%83% BC% E3% 82% BF% E5% 8C% 96% E3% 83% 86% E3% 82% B9% E3% 83% 88) était très facile à comprendre! J'ai été très utile mm

Épilogue

Il existe de nombreux articles sur le test de JUnit, mais il y a beaucoup d'articles sur les anciennes versions, donc j'espère que cela sera utile pour les débutants qui relèvent de Spring Boot et JUnit 5.

Recommended Posts

J'ai écrit un test avec Spring Boot + JUnit 5 maintenant
[Compatible JUnit 5] Ecrire un test en utilisant JUnit 5 avec Spring boot 2.2, 2.3
J'ai essayé GraphQL avec Spring Boot
J'ai essayé Flyway avec Spring Boot
Contrôleur de cadre de test Spring avec Junit
J'ai écrit un test CRUD avec SpringBoot + MyBatis + DBUnit (Partie 1)
Créer un formulaire de relation parent-enfant avec form_object (j'ai également écrit un test)
Effectuer un test de confirmation de transaction avec Spring Boot
J'ai créé un formulaire de recherche simple avec Spring Boot + GitHub Search API.
Exemple de code pour le test unitaire d'un contrôleur Spring Boot avec MockMvc
J'ai essayé l'initialisation paresseuse avec Spring Boot 2.2.0
Test de validation de classe de formulaire avec Spring Boot
[Spring Boot] Je suis tombé sur un test du nombre d'appels de méthode (framework Spock)
[LINE BOT] J'ai créé un Ramen BOT avec Java (Maven) + Heroku + Spring Boot (1)
Créez un site Web avec Spring Boot + Gradle (jdk1.8.x)
Testez le contrôleur avec Mock MVC dans Spring Boot
Créez une application de recherche simple avec Spring Boot
J'ai écrit un programme de jugement des nombres premiers en Java
[Java] Hello World avec Java 14 x Spring Boot 2.3 x JUnit 5 ~
Je voulais classer la botte à ressort dans un multi-projet
Créer un serveur API Web avec Spring Boot
Créer un environnement de développement Spring Boot avec docker
Faites un test unitaire avec Junit.
Télécharger avec Spring Boot
Comment effectuer UT avec Excel en tant que données de test avec Spring Boot + JUnit5 + DBUnit
J'ai essayé de cloner une application Web pleine de bugs avec Spring Boot
[RSpec] J'ai écrit un test pour télécharger une image de profil.
Comment écrire un test unitaire pour Spring Boot 2
Implémentez une API Rest simple avec Spring Security avec Spring Boot 2.0
Un mémorandum lors de la création d'un service REST avec Spring Boot
Créez un site de démonstration simple avec Spring Security avec Spring Boot 2.1
Ce à quoi j'étais accro lors du développement d'une application Spring Boot avec VS Code
J'ai écrit un code de test (Junit & mockit) pour le code qui appelle l'API AWS (Java)
Notez que j'étais accro au traitement par lots avec Spring Boot
Générer un code à barres avec Spring Boot
Hello World avec Spring Boot
Tester l'API Web avec junit
Démarrez avec Spring Boot
Bonjour tout le monde avec Spring Boot!
Exécutez LIFF avec Spring Boot
Connexion SNS avec Spring Boot
Spring Boot à partir de Docker
Hello World avec Spring Boot
Définir des cookies avec Spring Boot
Utiliser Spring JDBC avec Spring Boot
Ajouter un module avec Spring Boot
Premiers pas avec Spring Boot
Créer un micro service avec Spring Boot
Envoyer du courrier avec Spring Boot
J'ai essayé le guide d'introduction de Spring Boot [Accès aux données avec JPA]
Une histoire remplie des bases de Spring Boot (résolu)
Faisons une API simple avec EC2 + RDS + Spring boot ①
J'ai étudié Randoop, un générateur de classe de test JUnit pour Java.
J'ai essayé de démarrer avec Swagger en utilisant Spring Boot
Implémentez une API Rest simple avec Spring Security & JWT avec Spring Boot 2.0
Utilisez Spring Test + Mockito + JUnit 4 pour le test unitaire Spring Boot + Spring Retry
J'ai créé un système d'exemple MVC simple à l'aide de Spring Boot
[Java] Je souhaite tester l'entrée standard et la sortie standard avec JUnit
Implémentez un serveur API Web REST simple avec Spring Boot + MySQL
J'ai essayé le guide d'introduction de Spring Boot [Création d'un service Web RESTful]
Utiliser l'authentification de base avec Spring Boot