[JAVA] [JUnit 5] Ecrivez un test de validation avec Spring Boot! [Test de paramétrage]

introduction

salut! Il s'agit de la 5ème série à jouer avec Java à partir de zéro. Cette fois, nous allons faire une classe de test pour la validation que nous avons faite la dernière fois.

Si vous le gâchez, c'est le type de message Qiita qui a d'abord un exemple d'échec. Si vous voulez voir un exemple du test de paramétrage rapidement, veuillez passer à ◎ Bon exemple

Cliquez ici pour les articles jusqu'à la dernière fois ↓

  1. Création d'un environnement STS sur mac
  2. Hello World avec Spring Boot
  3. Créer une application Echo avec Spring Boot
  4. Créer une validation de formulaire avec Spring Boot

Synopsis jusqu'à la dernière fois

Les exigences de validation actuelles sont les suivantes. Des annotations sont ajoutées à la classe de formulaire pour vérifier les types de caractères suivants et le nombre de caractères.

--Types de caractères disponibles: alphanumérique demi-largeur uniquement

画面収録 2020-07-21 23.39.15.mov.gif

Environnement d'utilisation et version

[△ Mauvais exemple (1)] Copier et coller autre que la partie de paramétrage de la variable à tester et redondant

Puisque nous validons avec la classe de formulaire, nous allons créer une classe de test pour la classe de formulaire. Il y a quatre cas que je voudrais tester cette fois.

  1. Système normal (pas d'erreur)
  2. Système anormal (nombre de caractères incorrect)
  3. Système anormal (type de caractère non valide)
  4. Système anormal (nombre de caractères illégal et type de caractère incorrect)

Cependant, même dans le système normal, les caractères alphanumériques demi-largeur sont autorisés, donc si vous souhaitez effectuer un test plus rigoureux, vous voulez un modèle de données composé uniquement de chiffres, uniquement de caractères alphabétiques et de caractères alphanumériques. Je souhaite également créer des modèles de données tels que hiragana, katakana, kanji, caractères alphanumériques pleine largeur, symboles, etc. pour les erreurs de type de caractère anormales ... [^ 1]

Le code suivant a été créé à la hâte avec 3 modèles de système normal, 2 modèles de nombre incorrect de caractères et 2 modèles de type de caractère incorrect. Le test JUnit réussit toujours, mais l'exécution du test et la vérification des résultats sont très redondantes car le même code est répété (code de la plaque chauffante) ... De plus, les kanji et hiragana anormaux, les modèles de types de caractères mixtes et les types anormaux dans lesquels le nombre de caractères et le type de caractère sont invalides n'ont pas encore été implémentés. Si vous essayez de le compléter tel quel, la quantité de code augmentera encore.

[^ 1]: Strictement parlant, l'implémentation de ce formulaire est presque exclusivement pour utiliser la fonction de validation de javax (je n'ai pas créé ma propre validation etc.), il n'est donc pas nécessaire de le tester en profondeur côté utilisateur de la bibliothèque. Si quelque chose ne va pas avec cela, il y a un bogue fatal dans la bibliothèque javax elle-même. Pensez que ce n'est qu'une sous-carte pour vouloir introduire le test de paramétrage (rires)

EchoFormTest.java



package com.example.form;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNull;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;

@SpringBootTest
public class EchoFormTest {
	
	@Autowired
    Validator validator;

	private EchoForm testEchoForm = new EchoForm();
	private BindingResult bindingResult = new BindException(testEchoForm, "echoForm");
	
	/**
     *Système normal
     */
    @Test
    public void test_echo_Système normal_4 lettres ou plus() {
    	//La préparation du test
    	testEchoForm.setName("aaaa");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertNull(bindingResult.getFieldError());
    }

    @Test
    public void test_echo_Système normal_4 numéros ou plus() {
    	//La préparation du test
    	testEchoForm.setName("1111");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertNull(bindingResult.getFieldError());
    }

    @Test
    public void test_echo_Système normal_4 caractères alphanumériques ou plus() {
    	//La préparation du test
    	testEchoForm.setName("aa11");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertNull(bindingResult.getFieldError());
    }
    
    /**
     *Système anormal_ nombre insuffisant de caractères
     */
    @Test
    public void test_echo_Système anormal_Anglais demi-largeur 3 caractères() {
    	//La préparation du test
    	testEchoForm.setName("aaa");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertThat(bindingResult.getFieldError().toString()).contains("Doit comporter au moins 4 caractères.");
    }
    
    @Test
    public void test_echo_Système anormal_3 caractères demi-largeur() {
    	//La préparation du test
    	testEchoForm.setName("111");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertThat(bindingResult.getFieldError().toString()).contains("Doit comporter au moins 4 caractères.");
    }
    
    /**
     *Type de caractère_système anormal non valide
     */
    @Test
    public void test_echo_Système anormal_Hiragana() {
    	//La préparation du test
    	testEchoForm.setName("Ah ah");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertThat(bindingResult.getFieldError().toString()).contains("Seuls les caractères alphanumériques demi-largeur sont valides.");
    }
    
    @Test
    public void test_echo_Système anormal_Katakana() {
    	//La préparation du test
    	testEchoForm.setName("Aaaaaaa");
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertThat(bindingResult.getFieldError().toString()).contains("Seuls les caractères alphanumériques demi-largeur sont valides.");
    }
}

[× Mauvais exemple (2)] Boucle le modèle de données pour l'instruction

"Je souhaite modifier uniquement les données de test avec le même code pour l'exécution du test et la vérification des résultats ... C'est tout! Mettez les données de test dans un tableau et utilisez l'instruction for pour exécuter et vérifier les résultats pour chaque donnée! "

Lorsque vous lisez le livre d'introduction Java, il est facile de penser que les descriptions redondantes ont tendance à être résolues par des instructions for. Cela ne peut pas être aidé. Merci de dire non (← personne expérimentée).

Un code qui a l'air bien à première vue Pour une phrase qui peut être décrite plus courte que [△ mauvais exemple ①] ... Et savez-vous ce qui ne va pas avec ce code qui passe par tout même si vous l'exécutez réellement dans JUnit? ↓

EchoFormTest.java


   /**
     *Système normal
     */
    @Test
    public void test_echo_Système normal() {
    	String[] data = {"aaaa", "aa11", "1111"};
    	for(String testCase: data) {
    		//La préparation du test
    		testEchoForm.setName(testCase);	
    		//Mise en œuvre des tests
    		validator.validate(testEchoForm, bindingResult);
    		//Vérification des résultats
    		assertNull(bindingResult.getFieldError());
    	}
    }

En fait, dans cet exemple, il est bon que toutes les données de test se terminent normalement, mais si le test échoue avec les données au milieu, le test échouera sans que les données de test suivantes soient exécutées. Toutes les données ne peuvent pas être testées.

Par exemple, si vous essayez de faire qu'une erreur se produise dans les deuxième et troisième des trois données comme indiqué ci-dessous ...

EchoFormTest.java


    /**
     *Système normal
     */
    @Test
    public void test_echo_Système normal() {
    	String[] dataPattern = {"aaaa", "err", "bad"}; //Err ne réussit pas ce test car 3 caractères ou moins entraîneront une erreur
    	for(String testData: dataPattern) {
    		//La préparation du test
    		testEchoForm.setName(testData);	
    		//Mise en œuvre des tests
    		validator.validate(testEchoForm, bindingResult);
    		//Vérification des résultats
    		assertNull(bindingResult.getFieldError());
    	}
    }

Étant donné que le test échoue avec les secondes données, le journal n'affiche que la seconde erreur. Etant donné que la troisième donnée et les données suivantes ne sont pas testées en premier lieu, il n'est pas possible de déterminer si les données suivantes sont normales ou anormales.

スクリーンショット 2020-09-22 15.33.30.png

org.opentest4j.AssertionFailedError: expected: <null> but was: <Field error in object 'echoForm' on field 'name': rejected value [err]; codes [Size.echoForm.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [echoForm.name,name]; arguments []; default message [name],2147483647,4]; default message [Doit comporter au moins 4 caractères.]>
	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
	at org.junit.jupiter.api.AssertNull.failNotNull(AssertNull.java:48)
	at org.junit.jupiter.api.AssertNull.assertNull(AssertNull.java:37)
	at org.junit.jupiter.api.AssertNull.assertNull(AssertNull.java:32)
	at org.junit.jupiter.api.Assertions.assertNull(Assertions.java:258)
	at com.example.form.EchoFormTest.test_echo_Système normal(EchoFormTest.java:97)

Il serait effrayant de penser qu'il y aurait 100 ou 200 modèles de données après cela. Aussi redondant qu'il soit, on peut dire que [△ mauvais exemple ①] est toujours meilleur que [× mauvais exemple ②] car il peut remplir ses responsabilités en tant que code de test.

[◎ Bon exemple] Implémenté par test de paramétrage

Désolé je t'ai fait attendre! Voici un bon exemple. Implémentation en test paramétré.

EchoFormTest.java


    /**
     *Système normal
     */
    @ParameterizedTest
    @ValueSource(strings = {"aaaa", "aa11", "1111"})
    public void test_echo_Système normal(String s) {
        //La préparation du test
    	testEchoForm.setName(s);	
    	//Mise en œuvre des tests
    	validator.validate(testEchoForm, bindingResult);
    	//Vérification des résultats
    	assertNull(bindingResult.getFieldError());
    }

Il n'y a pas de code redondant comme [△ mauvais exemple ①]. De plus, ce qui est bien avec le paramétrage, c'est qu'il résout les problèmes de "tests suivants ne sont pas exécutés" et "je ne sais pas quelles données de test ont été exécutées" que j'ai vu dans [× Bad example (2)]. En regardant les résultats d'exécution ci-dessous, vous pouvez voir que les trois données de test ont été complétées normalement.

スクリーンショット 2020-09-22 15.56.07.png

Augmentez également les données et vérifiez si les première et quatrième données sont normales et si les deuxième et troisième données sont incorrectes.

EchoFormTest.java


    /**
     *Système normal
     */
    @ParameterizedTest
    @ValueSource(strings = {"aaaa", "err", "bad", "1111"}) //err et mauvais sont hors de caractères
    public void test_echo_Système normal(String s) {
        //La préparation du test
    	testEchoForm.setName(s);	
    	//Mise en œuvre des tests
    	validator.validate(testEchoForm, bindingResult);
    	//Vérification des résultats
    	assertNull(bindingResult.getFieldError());
    }

スクリーンショット 2020-09-22 16.03.07.png

Même après la deuxième erreur, les troisième et quatrième données ont été correctement vérifiées et la trace de la pile est sortie pour chaque erreur! JUnit5 est trop pratique ...

Je posterai également un exemple de système anormal.

EchoFormTest.java


    /**
     *Système anormal_ nombre insuffisant de caractères
     */
    @ParameterizedTest
    @ValueSource(strings = {"aaa", "111", "aa1"})
    public void test_echo_Système anormal_Nombre de caractères insuffisant(String s) {
    	//La préparation du test
    	testEchoForm.setName(s);
    	//Mise en œuvre des tests
        validator.validate(testEchoForm, bindingResult);
        //Vérification des résultats
        assertThat(bindingResult.getFieldError().toString()).contains("Doit comporter au moins 4 caractères.");

J'ai pu vérifier cela sans aucun problème!

スクリーンショット 2020-09-22 16.18.04.png

Veuillez également vous référer à la Qiita suivante (je l'ai utilisée comme référence cette fois!). Le test de paramétrage de JUnit 5 est super pratique

Ce sera un hasard, mais dans le cas de JUnit 4, le site suivant sera utile. https://javaworld.helpfulness.jp/post-81/ Je l'ai implémenté en utilisant @RunWith (Parameterized.class). Bien que la quantité de code soit supérieure à celle de JUnit5, le test de paramétrage peut être suffisamment implémenté dans JUnit4. Il peut également être utilisé avec un autre lanceur de test en le créant comme classe interne de @ RunWith (Enclosed.class).

en conclusion

Cette fois, nous avons examiné le test de paramétrage dans JUnit 5. Un mauvais exemple est la façon dont je l'ai écrit quand je ne connaissais pas l'existence du test paramétré lui-même ... Il est en fait facile de proposer un test avec une instruction for, donc si vous l'avez fait, envisagez de passer à un test paramétré!

Merci pour la lecture!

Recommended Posts

[JUnit 5] Ecrivez un test de validation avec Spring Boot! [Test de paramétrage]
[Compatible JUnit 5] Ecrire un test en utilisant JUnit 5 avec Spring boot 2.2, 2.3
J'ai écrit un test avec Spring Boot + JUnit 5 maintenant
Test de validation de classe de formulaire avec Spring Boot
Comment écrire un test unitaire pour Spring Boot 2
Écrire du code de test avec Spring Boot
Obtenez des résultats de validation avec Spring Boot
Contrôleur de cadre de test Spring avec Junit
Effectuer un test de confirmation de transaction avec Spring Boot
Exemple de code pour le test unitaire d'un contrôleur Spring Boot avec MockMvc
Écrivons un code de test pour la fonction de connexion avec Spring Boot
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
Écrivez rapidement un test RestController avec Spring Boot + Spock
[Java] Hello World avec Java 14 x Spring Boot 2.3 x JUnit 5 ~
[Java] Article pour ajouter une validation avec Spring Boot 2.3.1.
Créer un serveur API Web avec Spring Boot
Créer un environnement de développement Spring Boot avec docker
Validation personnalisée avec Spring
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
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
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
Test de validation d'élément unique de printemps
Envoyer du courrier avec Spring Boot
Modifier le message de validation Spring Boot
Une histoire remplie des bases de Spring Boot (résolu)
Faisons une API simple avec EC2 + RDS + 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
Implémentez un serveur API Web REST simple avec Spring Boot + MySQL
Utiliser l'authentification de base avec Spring Boot
Créons une application Web de gestion de livres avec Spring Boot part1
Ecrire un serveur réactif avec Micronaut
gRPC sur Spring Boot avec grpc-spring-boot-starter
Déploiement à chaud avec le développement Spring Boot
Créons une application Web de gestion de livres avec Spring Boot part3
Programmation Spring Boot avec VS Code
Jusqu'à "Hello World" avec Spring Boot
Créer une application d'enquête avec Spring Boot
Créons une application Web de gestion de livres avec Spring Boot part2
J'ai créé un formulaire de recherche simple avec Spring Boot + GitHub Search API.
(Intellij) Hello World avec Spring Boot
Créez une application avec Spring Boot