[JAVA] Effectuer un test de confirmation de transaction avec Spring Boot

introduction

L'équipe à laquelle j'appartiens a une règle selon laquelle s'il y a un problème, écrivez un code de test pour le reproduire (vérifiez la barre rouge) puis corrigez-le. L'autre jour, il y avait un problème de contrôle des transactions manquant, alors j'ai essayé d'écrire un code de test, mais comme j'étais confus, je vais l'organiser et le poster. Le code de test est répertorié sur Github (https://github.com/shimi58/transactiontest), veuillez donc vous y référer.

Environnement de développement

L'environnement construit sur Eclipse est le suivant. J'ai créé un projet Gradle et je l'ai passé par le chemin.

environnement version
Java 1.8
SpringBoot 2.2.6
MyBatis 2.1.0
H2 PostgresqlMode
Junit 5(Jupiter)

Code d'implémentation (classe de service)

Enregistrez les informations sur les employés (nom, numéro de téléphone, adresse e-mail) et mettez à jour le numéro de la table des employés vers la table de statut. C'est une source d'échantillons telle que.


/**
 * Service aux employés
 */
@Service
public class EmployeeService {

    @Autowired
    EmployeeRepository employeeRepository;

    /**
 * Inscription des employés
     */
 @Transactional // ← C'était une fuite
    public EmployeeNumber register(Employee employee) {

        employeeRepository.registerEmployee(employee);
        Employees employees = employeeRepository.findEmployees();

        EmployeeNumber employeeNumber = employees.number();
        employeeRepository.registerNumber(employeeNumber);

        return employeeNumber;

    }

}

Dans cet exemple de source, il est mis à jour en tant que table des employés → table des statuts, mais si la transaction n'est pas effective, si la mise à jour de la table des statuts échoue, elle est conservée dans la table des numéros et des statuts contenue dans la table des salariés. Le nombre de cas est incohérent.

À propos, la classe Controller sera mentionnée plus tard lorsque le code de test sera expliqué.

/**
 * Contrôleur des employés
 */
@RestController
@RequestMapping("/employees")
public class EmployeesController {

    @Autowired
    EmployeeService employeeService;

    /**
 * Inscription des employés
     */
    @RequestMapping(value = "/register", method = {RequestMethod.POST})
    public String regist(@RequestBody Employee employee) {

        EmployeeNumber employeeNumber = new EmployeeNumber(0);

        try {
            employeeNumber = employeeService.register(employee);
        } catch (Exception e) {

 System.out.println ("erreur de traitement");
        }
        return employeeNumber.toString();


    }
}

Comment tester

Utilisez ** @SpyBean **.

SpyBean est une fonction de Spring Boot, et c'est un Suguremono qui ne fait qu'une partie du traitement de la classe que vous souhaitez tester dans Mock. Dans le cas de cet exemple de source, mock the EmployeeRepository avec SpyBean et

--registerEmployee: processus d'inscription des employés → Mise en œuvre normale --findEmployees: Traitement du nombre de tables des employés → Exécution normale --registerNumber: Processus de mise à jour de la table d'état → Une erreur s'est produite

Je veux créer une situation comme celle-là.

Code de test

Le test est exécuté en appelant la classe Controller en tant que SpringBootTest. La classe Controller appelle la classe de service ci-dessus.

@SpringBootTest
public class EmployeesControllerTransactionTest {

    MockMvc mockMvc;

    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private EmployeesController employeesController;

 // Cible fictive
    @SpyBean
    private EmployeeRepository employeeRepository;


    /**
 * Test de transaction
     *
 * Lorsqu'une erreur se produit lors de la mise à jour du nombre d'employés après l'enregistrement des informations sur les employés dans le tableau Employé, <br>
 * Assurez-vous d'annuler l'enregistrement des informations sur les employés
     *
     * @throws Exception
     */
    @ParameterizedTest
 @CsvSource ({"Takao Hibi, 123-4345-2352, [email protected], 3"})
    public void testTransaction(String name, String phone, String mail, int expected)
            throws Exception {

        Employee employee = new Employee(name, phone, mail);


 // Convertir la requête au format Json
        String json = mapper.writeValueAsString(employee);

 // Paramètre d'occurrence d'erreur
        doThrow(new RuntimeException()).when(employeeRepository)
                .registerNumber(Mockito.any(EmployeeNumber.class));

        this.mockMvc = MockMvcBuilders.standaloneSetup(employeesController).build();

 // Émettre une demande
        MvcResult result = mockMvc.perform(
                post("/employees/register").contentType(MediaType.APPLICATION_JSON).content(json))
                .andExpect(status().isOk()).andReturn();

        String response = result.getResponse().getContentAsString();
        Employees employees = employeeRepository.findEmployees();

        System.out.println(response);
        System.out.println(employees.toString());

        EmployeeNumber actual = employees.number();

 // Parce qu'il sera annulé, vérifiez qu'il est à l'état 3 avant l'enregistrement
        assertEquals(expected, actual.getValue().intValue());
    }

Points de mise en œuvre des tests

@SpringBootTest
public class EmployeesControllerTransactionTest {

Il est indispensable car il ne fera pas de DI à moins que SpringBootTest ne soit attaché.

    @SpyBean
    private EmployeeRepository employeeRepository;

Déclarez le référentiel à moquer.

    @ParameterizedTest
 @CsvSource ({"Takao Hibi, 123-4345-2352, [email protected], 3"})

Bien que cela n'ait rien à voir avec cet article, vous pouvez utiliser CsvSource pour effectuer des tests de variation avec une méthode. J'avais une longue histoire de Junit4, donc j'ai été impressionné quand j'ai réalisé que je pouvais le faire. Au fait, le nom a été emprunté à Amazing Name Generator. C'est devenu un monde pratique. (Plus hors de propos.)

 // Paramètre d'occurrence d'erreur
        doThrow(new RuntimeException()).when(employeeRepository)
                .registerNumber(Mockito.any(EmployeeNumber.class));

Ici, il est déclaré qu'une RuntimeException sera générée lors du traitement de registerNumber.

this.mockMvc = MockMvcBuilders.standaloneSetup(employeesController).build();

Point Dohamari ①. Si vous ne faites pas standaloneSetup, mockMvc disparaîtra avec nullpo.

        MvcResult result = mockMvc.perform(
                post("/employees/register").contentType(MediaType.APPLICATION_JSON).content(json))
                .andExpect(status().isOk()).andReturn();

Point Dohamari ②. Si ce n'est pas status (). IsOk (), il s'envolera (devac ne sera pas retourné). Je me suis inquiété pendant une heure lorsque l'URL de la publication était incorrecte et que 404 a été renvoyé, et pourquoi la réponse de débogage n'a pas eu lieu.

Résultat de l'exécution du test

Lorsque j'ai exécuté le code de test, il s'est avéré être une merveilleuse barre verte! image.png

Au fait, si vous supprimez @Transactional dans la classe de service, image.png

Ouais, c'est une barre rouge. Si le nombre d'éléments dans la table des employés est différent d'un, une erreur d'assertion s'est produite et la transaction peut être confirmée.

finalement

Je regarderai seul en arrière.

Ce que j'ai trouvé

Que faire ensuite

Recommended Posts

Effectuer un test de confirmation de transaction avec Spring Boot
Test de validation de classe de formulaire avec Spring Boot
Télécharger avec Spring Boot
Testez le contrôleur avec Mock MVC dans Spring Boot
Générer un code à barres avec Spring Boot
Hello World avec Spring Boot
Implémenter GraphQL avec Spring Boot
Démarrez avec Spring Boot
[Compatible JUnit 5] Ecrire un test en utilisant JUnit 5 avec Spring boot 2.2, 2.3
Bonjour tout le monde avec Spring Boot!
Exécutez LIFF avec Spring Boot
Connexion SNS avec Spring Boot
Téléchargement de fichiers avec Spring Boot
Spring Boot commençant par copie
[JUnit 5] Ecrivez un test de validation avec Spring Boot! [Test de paramétrage]
Comment effectuer UT avec Excel en tant que données de test avec Spring Boot + JUnit5 + DBUnit
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
J'ai écrit un test avec Spring Boot + JUnit 5 maintenant
Envoyer du courrier avec Spring Boot
Utiliser l'authentification de base avec Spring Boot
gRPC sur Spring Boot avec grpc-spring-boot-starter
Créez une application avec Spring Boot 2
Déploiement à chaud avec le développement Spring Boot
Liaison de base de données avec doma2 (Spring boot)
Écrire du code de test avec Spring Boot
Programmation Spring Boot avec VS Code
Jusqu'à "Hello World" avec Spring Boot
Créer une application d'enquête avec Spring Boot
Obtenez des résultats de validation avec Spring Boot
(Intellij) Hello World avec Spring Boot
Créez une application avec Spring Boot
Google Cloud Platform avec Spring Boot 2.0.0
Utiliser DBUnit pour le test Spring Boot
J'ai essayé GraphQL avec Spring Boot
[Java] Intégration LINE avec Spring Boot
À partir de Spring Boot 0. Utilisez Spring CLI
J'ai essayé Flyway avec Spring Boot
Contrôleur de cadre de test Spring avec Junit
La coopération des messages a commencé avec Spring Boot
Exemple de code pour le test unitaire d'un contrôleur Spring Boot avec MockMvc
Hello World avec Eclipse + Spring Boot + Maven
Envoyez des notifications régulières avec LineNotify + Spring Boot
HTTPS avec Spring Boot et Let's Encrypt
Essayez d'utiliser Spring Boot avec VS Code
Le test Spring Boot @WebMvcTest active la sécurité par défaut de Spring Security
Démarrez le développement d'applications Web avec Spring Boot
Lancez l'application Nginx + Spring Boot avec docker-compose
J'ai essayé l'initialisation paresseuse avec Spring Boot 2.2.0
Implémenter CRUD avec Spring Boot + Thymeleaf + MySQL
Traitement asynchrone avec Spring Boot en utilisant @Async
Implémenter la fonction de pagination avec Spring Boot + Thymeleaf
(IntelliJ + gradle) Hello World avec Spring Boot
Utiliser le cache avec EhCashe 2.x avec Spring Boot