[JAVA] Utilisez Spring Test + Mockito + JUnit 4 pour le test unitaire Spring Boot + Spring Retry

Aperçu

Environnement de contrôle de fonctionnement

Liste du code source de l'exemple de programme

├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── sample
    │           ├── EchoController.java
    │           ├── EchoRepository.java
    │           └── EchoService.java
    └── test
        └── java
            └── sample
                └── EchoServiceTest.java

Fichier de construction Maven pom.xml

Cette fois, exécutez la compilation avec Maven. pom.xml est basé sur celui généré par Spring Initializr. Ajoutez spring-retry aux dépendances pour utiliser Spring Retry. Ajoutez également spring-boot-starter-aop car la classe AOP est requise lors de l'exécution. Ajoutez spring-boot-starter-test pour utiliser Spring Test.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.M4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>info.maigo.lab</groupId>
    <artifactId>sample</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sample</name>
    <description>Sample project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.2.4.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </pluginRepository>
    </pluginRepositories>

</project>

Code source

EchoController.java

Il s'agit d'une classe d'entrée de démarrage de Spring Boot (avec l'annotation @SpringBootApplication), ainsi que d'une classe Controller (avec l'annotation @RestController) qui reçoit une requête HTTP et renvoie une réponse. L'annotation @EnableRetry est spécifiée pour activer Spring Retry.

package sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
@EnableRetry
@RestController
public class EchoController {

    public static void main(String[] args) {
        SpringApplication.run(EchoController.class, args);
    }

    @Autowired
    private EchoService service;

    @RequestMapping("/{message}")
    public Map<String, Object> index(@PathVariable("message") String message) {
        return new HashMap<String, Object>() {
            {
                put("result", service.echo(message));
            }
        };
    }
}

EchoRepository.java

Classe de référentiel.

package sample;

import org.springframework.stereotype.Repository;

import java.util.Random;

@Repository
public class EchoRepository {

    public String echo(String message) {
        //Il y a une demi-chance qu'une exception se produise
        if (new Random().nextBoolean()) {
            return message;
        } else {
            throw new RuntimeException("Failure");
        }
    }
}

EchoService.java

Classe de service. Lorsqu'une RuntimeException se produit dans une méthode qui spécifie l'annotation Spring Retry @Retryable, la même méthode est essayée jusqu'à 3 fois.

package sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;

@Service
public class EchoService {

    @Autowired
    private EchoRepository repository;

    /**
     *Renvoie le message spécifié.
     *Parfois, cela échoue, mais j'essaye jusqu'à 3 fois.
     * @message de paramétrage
     * @message de retour
     */
    @Retryable(
            value = {RuntimeException.class},
            maxAttempts = 3,
            backoff = @Backoff(delay = 1000))
    public String echo(String message) {
        System.out.println("EchoService#echo: " + message);
        return repository.echo(message);
    }

    @Recover
    public String recover(RuntimeException e, String message) {
        System.out.println("EchoService#recover: " + message);
        throw e;
    }
}

EchoServiceTest.java

Classe de test pour la classe EchoService. Créez un objet fictif d'EchoRepository et testez le comportement d'EchoService.

package sample;

import org.junit.Test;
import org.junit.runner.RunWith;
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.context.junit4.SpringRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;

@RunWith(SpringRunner.class) //Utilisez JUnit pour le printemps
@SpringBootTest //Lancez Spring Boot et testez
public class EchoServiceTest {

    @Autowired
    private EchoService service;

    //Ajouter une maquette à ApplicationContext
    // (Remplacez les objets existants, le cas échéant)
    @MockBean
    private EchoRepository mockRepository;

    @Test
    public void testSuccess() {
        //Préparez une maquette d'EchoRepository
        //Cette simulation renvoie une valeur normalement
        String message = "Zero";
        doReturn(message).when(mockRepository).echo(message);
        //tester
        assertEquals(message, service.echo(message));
    }

    @Test
    public void testFairureSuccess() {
        //Préparez une maquette d'EchoRepository
        //Cette simulation lève une exception une fois, puis renvoie la valeur normalement
        String message = "Uno";
        doThrow(new RuntimeException("Failure"))
            .doReturn(message)
            .when(mockRepository).echo(message);
        //tester
        assertEquals(message, service.echo(message));
    }

    @Test
    public void testFairureFairureSuccess() {
        //Préparez une maquette d'EchoRepository
        //Ce simulacre lève une exception deux fois, puis renvoie une valeur normalement
        String message = "Due";
        doThrow(new RuntimeException("Failure"))
            .doThrow(new RuntimeException("Failure"))
            .doReturn(message)
            .when(mockRepository).echo(message);
        //tester
        assertEquals(message, service.echo(message));
    }

    @Test(expected = RuntimeException.class) //En supposant une exception RuntimeException
    public void testFairureFairureFairure() {
        //Préparez une maquette d'EchoRepository
        //Cette simulation lève une exception 3 fois
        String message = "Tre";
        doThrow(new RuntimeException("Failure"))
            .doThrow(new RuntimeException("Failure"))
            .doThrow(new RuntimeException("Failure"))
            .when(mockRepository).echo(message);
        //tester
        service.echo(message);
    }
}

Lancer le test

Entrez la commande mvn test pour lancer Spring Boot et exécuter le test.

$ mvn test
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< info.maigo.lab:sample >------------------------
[INFO] Building sample 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
(Omission)
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::             (v2.2.0.M4)

(Omission)
2019-07-20 20:12:34.687  INFO 25426 --- [           main] sample.EchoServiceTest                   : Started EchoServiceTest in 3.407 seconds (JVM running for 4.983)
EchoService#echo: Due
EchoService#echo: Due
EchoService#echo: Due
EchoService#echo: Tre
EchoService#echo: Tre
EchoService#echo: Tre
EchoService#recover: Tre
EchoService#echo: Uno
EchoService#echo: Uno
EchoService#echo: Zero
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.643 s - in sample.EchoServiceTest
2019-07-20 20:12:39.930  INFO 25426 --- [       Thread-1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  14.650 s
[INFO] Finished at: 2019-07-20T20:12:40+09:00
[INFO] ------------------------------------------------------------------------

Matériel de référence

Recommended Posts

Utilisez Spring Test + Mockito + JUnit 4 pour le test unitaire Spring Boot + Spring Retry
Utiliser DBUnit pour le test Spring Boot
Comment écrire un test unitaire pour Spring Boot 2
Annotations fréquentes pour les tests Spring Boot
Faites un test unitaire avec Junit.
Comment faire un test unitaire Java (JUnit & Mockito & PowerMock)
[Compatible JUnit 5] Ecrire un test en utilisant JUnit 5 avec Spring boot 2.2, 2.3
Spring Boot + Springfox springfox-boot-starter 3.0.0 Utilisation
Utiliser Spring JDBC avec Spring Boot
Spring Boot pour l'apprentissage des annotations
Test unitaire Java avec Mockito
Exemple de code pour le test unitaire d'un contrôleur Spring Boot avec MockMvc
[Spring Boot] Jusqu'à ce que @Autowired soit exécuté dans la classe de test [JUnit5]
Utiliser l'authentification de base avec Spring Boot
Comment faire un test unitaire de Spring AOP
Spring Boot pour la première fois
Écrire du code de test avec Spring Boot
Comment utiliser ModelMapper (Spring boot)
À partir de Spring Boot 0. Utilisez Spring CLI
Contrôleur de cadre de test Spring avec Junit
Solution de contournement pour que Command Line Runner fonctionne avec JUnit dans Spring Boot
[Pour usage interne] Pour ceux affectés au projet Spring Boot (en construction)
Ordre du prétraitement et du post-traitement du test unitaire JUnit
[Rails] Code de test unitaire pour le modèle utilisateur
Bibliothèque de tests unitaires Java Artery-Easy to use
Effectuer un test de confirmation de transaction avec Spring Boot
Le test Spring Boot @WebMvcTest active la sécurité par défaut de Spring Security
Mémorandum WebMvcConfigurer de Spring Boot 2.0 (printemps 5)
Utiliser la méthode de requête DynamoDB avec Spring Boot
Utiliser le cache avec EhCashe 2.x avec Spring Boot
Comment effectuer UT avec Excel en tant que données de test avec Spring Boot + JUnit5 + DBUnit