7 conseils pour les tests unitaires Java
Les tests sont un aspect très important du développement et peuvent déterminer dans une large mesure le sort d'une application. De bons tests peuvent détecter les problèmes qui provoquent un crash précoce de votre application, mais des tests médiocres entraînent souvent des échecs et des temps d'arrêt à tout moment.
Bien qu'il existe trois principaux types de tests logiciels : les Tests unitaires, les tests fonctionnels et les tests d'intégration, dans cet article de blog, nous discuterons des tests unitaires au niveau du développeur. Avant d’entrer dans les détails, passons en revue les détails de chacun de ces trois tests.
Types de tests de développement logiciel
Les tests unitaires sont utilisés pour tester des composants de code individuels et garantir que le code fonctionne comme prévu. Les tests unitaires sont écrits et exécutés par les développeurs. La plupart du temps, un framework de test comme JUnit ou TestNG est utilisé. Les cas de test sont généralement écrits au niveau de la méthode et exécutés via l'automatisation.
Les tests d'intégration vérifient si le système fonctionne dans son ensemble. Les tests d'intégration sont également effectués par les développeurs, mais au lieu de tester un seul composant, ils sont conçus pour tester plusieurs composants. Le système se compose de nombreux composants individuels tels que le code, la base de données, le serveur Web, etc. Les tests d'intégration peuvent révéler des problèmes tels que le câblage des composants, l'accès au réseau, les problèmes de base de données, etc.
Les tests fonctionnels vérifient si chaque fonctionnalité est correctement implémentée en comparant les résultats d'une entrée donnée à la spécification. En règle générale, cela ne se situe pas au niveau du développeur. Les tests fonctionnels sont effectués par une équipe de test distincte. Les cas de test sont rédigés sur la base de spécifications et les résultats réels sont comparés aux résultats attendus. Il existe plusieurs outils disponibles pour les tests fonctionnels automatisés, tels que Selenium et QTP.
Comme mentionné précédemment, les tests unitaires aident les développeurs à déterminer si le code fonctionne correctement. Dans cet article de blog, je fournirai des conseils utiles pour les tests unitaires en Java.
1. Utiliser des frameworks pour les tests unitaires
Java fournit plusieurs frameworks pour les tests unitaires. TestNG et JUnit sont les frameworks de test les plus populaires. Quelques fonctionnalités importantes de JUnit et TestNG :
Facile à configurer et à exécuter.
Prend en charge les commentaires.
Permet d'ignorer ou de regrouper et d'exécuter certains tests ensemble.
prend en charge les tests paramétrés, c'est-à-dire l'exécution de tests unitaires en spécifiant différentes valeurs au moment de l'exécution.
Prend en charge l'exécution automatisée des tests en s'intégrant à des outils de build tels que Ant, Maven et Gradle.
EasyMock est un framework moqueur qui complète les frameworks de tests unitaires tels que JUnit et TestNG. EasyMock lui-même n'est pas un framework complet. Cela ajoute simplement la possibilité de créer des objets fictifs pour des tests plus faciles. Par exemple, une méthode que nous souhaitons tester peut appeler une classe DAO qui récupère les données d'une base de données. Dans ce cas, EasyMock peut être utilisé pour créer un MockDAO qui renvoie des données codées en dur. Cela nous permet de tester facilement nos méthodes prévues sans avoir à nous soucier de l'accès à la base de données.
2. Utilisez le développement piloté par les tests avec prudence !
Le développement piloté par les tests (TDD) est un processus de développement logiciel dans lequel nous écrivons des tests basés sur les exigences avant de commencer tout codage. Puisqu’il n’y a pas encore de codage, le test échouera dans un premier temps. Écrivez ensuite la quantité minimale de code pour réussir le test. Refactorisez ensuite le code jusqu'à ce qu'il soit optimisé.
L'objectif est d'écrire des tests qui couvrent toutes les exigences, plutôt que d'écrire du code qui pourrait même ne pas répondre aux exigences. TDD est génial car il donne un code modulaire simple et facile à maintenir. La vitesse globale de développement est accélérée et les défauts sont facilement détectés. De plus, les tests unitaires sont créés comme un sous-produit de l'approche TDD.
Cependant, le TDD peut ne pas convenir à toutes les situations. Dans les projets aux conceptions complexes, se concentrer sur la conception la plus simple pour faciliter la réussite des cas de test sans anticiper peut conduire à d’énormes changements de code. De plus, les méthodes TDD sont difficiles à utiliser pour les systèmes qui interagissent avec des systèmes existants, des applications GUI ou des applications qui fonctionnent avec des bases de données. De plus, les tests doivent être mis à jour à mesure que le code change.
Par conséquent, avant de décider d'adopter l'approche TDD, les facteurs ci-dessus doivent être pris en compte et des mesures doivent être prises en fonction de la nature du projet.
3. Mesurer la couverture du code
La couverture du code mesure (exprimée en pourcentage) la quantité de code exécutée lors de l'exécution de tests unitaires. Généralement, le code avec une couverture élevée a moins de chances de contenir des bogues non détectés, car une plus grande partie de son code source est exécutée pendant les tests. Voici quelques bonnes pratiques pour mesurer la couverture de code :
Utilisez un outil de couverture de code tel que Clover, Corbetura, JaCoCo ou Sonar. L'utilisation d'outils peut améliorer la qualité de vos tests car ils peuvent signaler les zones de votre code qui ne sont pas testées, vous permettant ainsi de développer des tests supplémentaires pour couvrir ces domaines.
Chaque fois qu'une nouvelle fonctionnalité est écrite, écrivez immédiatement une nouvelle couverture de test.
Assurez-vous qu'il existe des cas de test couvrant toutes les branches du code, c'est-à-dire les instructions if/else.
Une couverture de code élevée ne garantit pas des tests parfaits, alors soyez prudent !
La méthode concat ci-dessous accepte une valeur booléenne en entrée et transmet en outre deux chaînes uniquement si la valeur booléenne est vraie :
public String concat(boolean append, String a,String b) { String result = null; If (append) { result = a + b; } return result.toLowerCase(); }
Ce qui suit est la méthode ci-dessus Cas de test pour :
@Test public void testStringUtil() { String result = stringUtil.concat(true, "Hello ", "World"); System.out.println("Result is "+result); }
Dans ce cas, la valeur du test exécuté est vraie. Une fois le test exécuté, il réussira. Lorsque l'outil de couverture de code est exécuté, il affichera une couverture de code à 100 % car tout le code de la méthode concat a été exécuté. Cependant, si le test s'exécute avec une valeur false, une NullPointerException sera levée. Ainsi, une couverture de code à 100 % ne signifie pas vraiment que les tests couvrent tous les scénarios, ni que les tests sont bons.
4. Externalisez autant que possible les données de test
Avant JUnit4, les données du scénario de test à exécuter devaient être codées en dur dans le scénario de test. Cela entraîne une limitation : pour exécuter des tests avec des données différentes, le code du scénario de test doit être modifié. Cependant, JUnit4 ainsi que TestNG prennent en charge l'externalisation des données de test afin que les cas de test puissent être exécutés sur différents ensembles de données sans modifier le code source.
La classe MathChecker suivante a des méthodes pour vérifier si un nombre est impair :
public class MathChecker { public Boolean isOdd(int n) { if (n%2 != 0) { return true; } else { return false; } } }
Ce qui suit est le scénario de test TestNG pour la classe MathChecker :
public class MathCheckerTest { private MathChecker checker; @BeforeMethod public void beforeMethod() { checker = new MathChecker(); } @Test @Parameters("num") public void isOdd(int num) { System.out.println("Running test for "+num); Boolean result = checker.isOdd(num); Assert.assertEquals(result, new Boolean(true)); } }
TestNG
Ce qui suit est testng.xml (le fichier de configuration de TestNG) qui contient les données pour lesquelles les tests doivent être exécutés :
<?xml version="1.0" encoding="UTF-8"?> <suite name="ParameterExampleSuite" parallel="false"> <test name="MathCheckerTest"> <classes> <parameter name="num" value="3"></parameter> <class name="com.stormpath.demo.MathCheckerTest"/> </classes> </test> <test name="MathCheckerTest1"> <classes> <parameter name="num" value="7"></parameter> <class name="com.stormpath.demo.MathCheckerTest"/> </classes> </test> </suite>
Comme on peut le voir, dans ce cas les tests seront exécutés deux fois, une fois chacun pour les valeurs 3 et 7. En plus de spécifier les données de test via des fichiers de configuration XML, les données de test peuvent également être fournies dans les classes via les annotations DataProvider.
JUnit
Semblable à TestNG, les données de test peuvent également être externalisées pour être utilisées avec JUnit. Ce qui suit est un cas de test JUnit pour la même classe MathChecker que ci-dessus :
@RunWith(Parameterized.class) public class MathCheckerTest { private int inputNumber; private Boolean expected; private MathChecker mathChecker; @Before public void setup(){ mathChecker = new MathChecker(); } // Inject via constructor public MathCheckerTest(int inputNumber, Boolean expected) { this.inputNumber = inputNumber; this.expected = expected; } @Parameterized.Parameters public static Collection<Object[]> getTestData() { return Arrays.asList(new Object[][]{ {1, true}, {2, false}, {3, true}, {4, false}, {5, true} }); } @Test public void testisOdd() { System.out.println("Running test for:"+inputNumber); assertEquals(mathChecker.isOdd(inputNumber), expected); } }
Comme on peut le voir, les données de test sur lesquelles le test doit être effectué sont spécifiées par la méthode getTestData(). Cette méthode peut être facilement modifiée pour lire les données à partir d'un fichier externe au lieu de coder en dur les données.
5. Utilisez des assertions au lieu des instructions Print
De nombreux développeurs novices ont l'habitude d'écrire des instructions System.out.println après chaque ligne de code pour vérifier si le code est exécuté correctement. Cette pratique s'étend souvent aux tests unitaires, ce qui entraîne un code de test encombré. Outre la confusion, cela nécessite une intervention manuelle du développeur pour vérifier le résultat imprimé sur la console afin de vérifier si le test s'est exécuté avec succès. Une meilleure approche consiste à utiliser des assertions qui indiquent automatiquement les résultats des tests.
La classe StringUti ci-dessous est une classe simple avec une méthode qui connecte deux caractères d'entrée et renvoie le résultat :
public class StringUtil { public String concat(String a,String b) { return a + b; } }
Voici deux des méthodes ci-dessus Tests unitaires :
@Test public void testStringUtil_Bad() { String result = stringUtil.concat("Hello ", "World"); System.out.println("Result is "+result); } @Test public void testStringUtil_Good() { String result = stringUtil.concat("Hello ", "World"); assertEquals("Hello World", result); }
testStringUtil_Bad sera toujours réussi car il n'a aucune assertion. Les développeurs doivent vérifier manuellement la sortie du test sur la console. testStringUtil_Good échouera si la méthode renvoie des résultats incorrects et ne nécessite pas l'intervention du développeur.
6. Construisez des tests avec des résultats déterministes
Certaines méthodes n'ont pas de résultats déterministes, c'est-à-dire que le résultat de la méthode n'est pas connu à l'avance et peut changer à chaque fois. Par exemple, considérons le code suivant, qui possède une fonction complexe et une méthode qui calcule le temps en millisecondes nécessaire pour exécuter la fonction complexe :
public class DemoLogic { private void veryComplexFunction(){ //This is a complex function that has a lot of database access and is time consuming //To demo this method, I am going to add a Thread.sleep for a random number of milliseconds try { int time = (int) (Math.random()*100); Thread.sleep(time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public long calculateTime(){ long time = 0; long before = System.currentTimeMillis(); veryComplexFunction(); long after = System.currentTimeMillis(); time = after - before; return time; } }
Dans ce cas, chaque Chaque fois que la méthode calculateTime est exécutée, elle renvoie une valeur différente. L'écriture de cas de test pour cette méthode ne sera d'aucune utilité puisque le résultat de cette méthode est variable. Par conséquent, la méthode de test ne sera pas en mesure de vérifier le résultat d’une exécution particulière.
7. En plus des scénarios positifs, testez les scénarios négatifs et les cas extrêmes.
En règle générale, les développeurs consacrent beaucoup de temps et d'efforts à l'écriture de cas de test pour s'assurer que l'application fonctionne comme prévu. Cependant, il est également important de tester les cas de tests négatifs. Les scénarios de test négatifs font référence à des scénarios de test qui testent si le système peut gérer des données non valides. Par exemple, considérons une fonction simple qui lit une valeur alphanumérique de longueur 8, saisie par l'utilisateur. En plus des valeurs alphanumériques, les cas de test négatifs suivants doivent être testés :
Valeurs non alphanumériques spécifiées par l'utilisateur telles que les caractères spéciaux.
Valeur nulle spécifiée par l'utilisateur.
Valeur spécifiée par l'utilisateur supérieure ou inférieure à 8 caractères.
De même, les cas de tests limites testent si le système est adapté aux valeurs extrêmes. Par exemple, si l'utilisateur souhaite saisir une valeur numérique comprise entre 1 et 100, alors 1 et 100 sont les valeurs limites et il est très important de tester le système pour ces valeurs.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds



Guide de la racine carrée en Java. Nous discutons ici du fonctionnement de Square Root en Java avec un exemple et son implémentation de code respectivement.

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Guide du numéro Armstrong en Java. Nous discutons ici d'une introduction au numéro d'Armstrong en Java ainsi que d'une partie du code.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est
