JavaRush /Blog Java /Random-FR /JUnit pour JavaRush ou un peu sur les tests à la maison.
Sdu
Niveau 17

JUnit pour JavaRush ou un peu sur les tests à la maison.

Publié dans le groupe Random-FR
Fatigué de saisir des dizaines de fois des données de test dans la console pour vérifier votre tâche ? Bienvenue chez le chat, je vais vous dire ce que vous pouvez en faire. Le but ultime de ce matériel sera d'automatiser le lancement de la tâche en cours de résolution avec divers paramètres et de vérifier les résultats sans apporter de modifications à son code source. Comme vous l'avez probablement déjà compris d'après le titre, notre principal assistant dans cette affaire assez simple sera JUnit . Si vous n'avez pas encore entendu parler des tests unitaires et des tests unitaires , je vous propose de faire une petite pause et de vous familiariser avec ces concepts, heureusement il y a suffisamment d'informations sur Internet. Non, tu ne veux pas ? Bon, d'accord, je pense que cela ne deviendra pas un gros problème pour comprendre ce qui se passe. Après tout, savez-vous ce qu’est un test et les tests en général ? Vous faites cela à chaque fois que vous lancez votre tâche, saisissez les données initiales et comparez le résultat obtenu avec ce que vous attendiez de voir.
Bonjour, monde JUnit !
Qu’est-ce que JUnit ? Sur le site officiel du projet , nous pouvons lire la description suivante :
JUnit est un framework simple pour écrire des tests répétables. Il s'agit d'une instance de l'architecture xUnit pour les frameworks de tests unitaires.
Pour nous, cela signifie la possibilité d'écrire des classes spécialement conçues dont les méthodes interagiront avec notre programme, compareront le résultat obtenu avec celui de référence et nous informeront si elles ne correspondent pas. Pour comprendre le principe, prenons un exemple simple. Supposons que nous ayons une classe auxiliaire dont l'une des méthodes prend deux variables de type int et renvoie leur somme : JUnit pour JavaRush ou un peu sur les tests à la maison.  - 1 c'est la fonctionnalité que nous allons essayer de tester. Heureusement, notre IDEA préférée a déjà tout ce dont vous avez besoin pour créer rapidement des tests, il suffit de placer le curseur dans la ligne de déclaration de classe, d'appuyer sur "Alt + Entrée" et de sélectionner "Créer un test" dans le menu contextuel : JUnit pour JavaRush ou un peu sur les tests à la maison.  - 2 Après avoir précisé où vous devez créer un test, IDEA suggère de choisir une bibliothèque de test (dans ce matériel, j'utilise JUnit4 ; pour que les classes de la bibliothèque soient connectées au projet, vous devez cliquer sur le bouton « Corriger »), des méthodes à tester et des méthodes supplémentaires choix. JUnit pour JavaRush ou un peu sur les tests à la maison.  - 3 L'EDI va créer un modèle de classe de test : ClassName = TestClassName + "Test" MethodName = "test" + TestMethodName JUnit pour JavaRush ou un peu sur les tests à la maison.  - 4 Il nous suffit de remplir le corps de la méthode. Les méthodes dites « Assertions » , fournies par JUnit , y contribueront . De manière simplifiée, leur travail ressemble à ceci : le résultat attendu et le résultat de l'appel de la méthode testée sont transmis à la méthode .assert* ; pour plus de commodité, vous pouvez ajouter un message explicatif comme premier paramètre. Si les paramètres ne correspondent pas lors du test, vous en serez informé. Vous pouvez lancer une classe de test pour l'exécuter comme une classe normale, je préfère utiliser la combinaison de touches Ctrl+Shift+F10 JUnit pour JavaRush ou un peu sur les tests à la maison.  - 5
Précisons la tâche
En théorie, tout est simple et beau, mais dans le cadre de l’exemple proposé, ce n’est pas vraiment nécessaire ; on peut faire confiance à l’ordinateur pour additionner deux nombres. Nous sommes plus intéressés par la façon dont les choses se passeront avec de vrais problèmes résolus par les étudiants de JavaRush ; par exemple, je suggère de prendre le niveau bien-aimé 05.lesson12.bonus03.
/* Problème sur les algorithmes Écrivez un programme qui : 1. entre le nombre N > 0 depuis la console 2. puis entre N nombres depuis la console 3. affiche le maximum des N nombres saisis. */
Nous devons écrire trois tests, pour des nombres positifs, négatifs et un ensemble mixte.
Plus on s'enfonce dans la forêt...
C'est là que quelques surprises nous attendent : public class UtilApp { public static void main(String[] args) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); //напишите здесь ваш code int n; int maximum; /* Конечно же я не буду размещать решение задачи ;) Код приведенный тут переработан для наглядности, и не в коем случае не означает что он должен присутствовать в "правильном решении" */ System.out.println(maximum); } }
  • La logique du programme est placée dans la méthode main()
  • Les données source ne sont pas transmises à la méthode, mais sont saisies à partir du clavier.
  • La méthode main() ne renvoie pas le résultat, mais le renvoie à la console.
Si le premier point n'est pas particulièrement problématique (on peut appeler la méthode main() comme d'habitude), alors les deux suivants nous obligent à approfondir le sujet et à mettre notre cerveau à rude épreuve. J'ai trouvé plusieurs solutions au problème :
  1. Déplacer la logique pour trouver le maximum dans une méthode distincte.
    • Avantages : Approche correcte en termes de refactoring
    • Inconvénients : Le programme est envahi par le code, les structures inutiles, au moins un tableau ou une ArrayList est ajouté (selon les goûts et la couleur...). Seul le mécanisme permettant de trouver le maximum est testé ; les entrées et sorties de données ne sont pas vérifiées.
  2. Écriture de wrappers pour System.in/System.out.
    • Avantages : Nous n'utilisons pas de bibliothèques tierces.
    • Inconvénients : Le parcours n’est pas destiné aux débutants. La complexité relative de la mise en œuvre du test ; la quantité de code dans le test peut être supérieure à celle de la tâche testée.
  3. Utilisation de bibliothèques supplémentaires pour les tests.
    • Avantages : Code propre dans les tests, relative facilité d'écriture d'un test. Le code source de la classe testée n'est pas modifié.
    • Inconvénients : Nécessité de connecter des bibliothèques tierces au projet.
Pour être honnête, j’ai le plus aimé la troisième option, alors essayons de la mettre en œuvre.
Règles du système
Une courte recherche m'a conduit à la page http://stefanbirkner.github.io/system-rules/ , et il est immédiatement devenu clair que c'était ce dont j'avais besoin.
Une collection de règles JUnit pour tester le code qui utilise java.lang.System.
Alors, téléchargeons la bibliothèque . Téléchargez la bibliothèque Commons IO requise pour que les règles système fonctionnent . Nous connectons les deux bibliothèques à notre projet (Fichier -> Structure du projet -> Bibliothèques -> + -> Java) et commençons à sculpter : Après le lancement, notre tâche vous demande de saisir N+1 nombres depuis la console, où le premier nombre vous l'indique combien de numéros le suivront. Dans les règles système, la classe TextFromStandardInputStream est utilisée à ces fins. Dans un premier temps, nous devons ajouter un champ de ce type à notre classe de test et le marquer avec l'annotation @Rule : @Rule public final TextFromStandardInputStream systemInMock = emptyStandardInputStream(); Ensuite, directement dans la méthode de test, nous indiquons les données nécessaires : systemInMock.provideText("4\n2\n6\n1\n3\n"); Comme vous pouvez le constater, les nombres sont transmis sous forme de texte et sont séparés par des traits d'union "\n". Sur cette base, il s'avère que N sera égal à 4 et nous rechercherons le maximum à partir des nombres {2, 6, 1, 3}. Ensuite, nous devons créer une instance de la classe testée et appeler la méthode main(). Notre programme lit les données de systemInMock, les traite et imprime le résultat, et tout ce que nous avons à faire est de les lire et de les comparer avec le standard. Pour ce faire, les règles système nous fournissent la classe StandardOutputStreamLog. Nous ajoutons un champ du type spécifié : @Rule public final StandardOutputStreamLog log = new StandardOutputStreamLog(); Vous pouvez lire les données imprimées en utilisant la méthode .getLog(), alors que vous devez prendre en compte la présence de caractères de nouvelle ligne, les options finales peuvent être comme ceci : assertEquals("{2, 6, 1, 3}, max = 6", "6", log.getLog().trim()); // or assertEquals("{2, 6, 1, 3}, max = 6", "6\r\n", log.getLog()); Entre les tests, afin de évitez la superposition de données, vous devez effacer le journal log.clear(); Le texte intégral de ma classe de test : import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.StandardOutputStreamLog; import org.junit.contrib.java.lang.system.TextFromStandardInputStream; import static org.junit.Assert.*; import static org.junit.contrib.java.lang.system.TextFromStandardInputStream.emptyStandardInputStream; public class UtilAppTest { @Rule public final TextFromStandardInputStream systemInMock = emptyStandardInputStream(); @Rule public final StandardOutputStreamLog log = new StandardOutputStreamLog(); @Test public void testAddition() throws Exception { systemInMock.provideText("4\n2\n6\n1\n3\n"); UtilApp utilApp = new UtilApp(); utilApp.main(new String[]{}); assertEquals("{2, 6, 1, 3}, max = 6", "6", log.getLog().trim()); systemInMock.provideText("5\n-100\n-6\n-15\n-183\n-1\n"); log.clear(); utilApp.main(new String[]{}); assertEquals("{-100, -6, -15, -183, -1}, max = -1", "-1", log.getLog().trim()); systemInMock.provideText("3\n2\n0\n-1\n"); log.clear(); utilApp.main(new String[]{}); assertEquals("{2, 0, -1}, max = 2", "2", log.getLog().trim()); } } Nous lançons et apprécions. -=!!! IMPORTANT !!!=- Ce matériel est fourni à titre informatif UNIQUEMENT ; je ne garantis pas la réussite du test de la tâche sur le serveur s'il y a une classe superflue dans le package avec la tâche. Avant d'envoyer une tâche pour vérification au serveur, supprimez tout ce qui est superflu : fichiers inutiles, classes inutiles, code commenté. La réussite des tests que vous avez créés ne garantit pas la réussite des tests sur le serveur. Je n'ai délibérément pas mâché le matériel théorique : la théorie des tests unitaires, les annotations JUnit, l'assertion, etc., tout le matériel est dans les liens fournis dans le texte. Peut-être avez-vous vos propres façons de tester les tâches, je me ferai un plaisir d'en discuter avec vous dans les commentaires.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION