web-dev-qa-db-fra.com

JUNIT teste les méthodes vides

J'ai une classe Java pleine de méthodes void et je souhaite effectuer des tests unitaires pour obtenir une couverture maximale du code.

Par exemple j'ai cette méthode:

protected static void checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
}

C'est mal nommé pour une raison parce que j'ai traduit le code pour une meilleure compréhension. Chaque méthode vérifie si les arguments sont valides et bien écrits. 

Exemple :

private static void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        ErrorFile.errorMessages.add("There is a dollar sign in the specified parameter");
    }
}

Mon test unitaire couvre bien les petites méthodes car je leur demande de vérifier si le fichier d'erreur contient le message d'erreur, mais je ne vois pas comment tester ma méthode checkIfValidElements, il ne retourne rien ou ne change rien. Lorsque j'utilise la couverture de code avec Maven, cela me dit que le test unitaire ne couvre pas cette partie de ma classe.

Le seul moyen que je vois est de changer cette méthode pour renvoyer une valeur int ou bollean, comme ceci:

protected static int checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
    return 0;
}

Avec cette méthode, je peux faire une affirmation égale, mais il me semble inutile de le faire. Le problème est que j'ai quelques classes qui sont conçues comme ça et que cela abaisse ma couverture en tests unitaires,%. 

50
metraon

Je veux faire un test unitaire pour obtenir une couverture maximale du code

La couverture de code ne doit jamais être le objectif d'écrire des tests unitaires. Vous devez écrire des tests unitaires pour prouver que votre code est correct, ou pour mieux le concevoir, ou pour aider une autre personne à comprendre ce que le code est censé faire.

mais je ne vois pas comment je peux tester ma méthode checkIfValidElements, elle ne retourne rien ou ne change rien. 

Eh bien, vous devriez probablement donner quelques tests qui, entre eux, vérifient que les 7 méthodes sont appelées correctement - avec un argument invalide et avec un argument valide, en vérifiant les résultats de ErrorFile à chaque fois.

Par exemple, supposons que quelqu'un ait supprimé l'appel à:

method4(arg1, arg2);

... ou modifié accidentellement l'ordre des arguments:

method4(arg2, arg1);

Comment remarqueriez-vous ces problèmes? Allez de là et concevez des tests pour le prouver.

54
Jon Skeet

Si votre méthode n'a aucun effet secondaire et ne renvoie rien, elle ne fait rien. 

Si votre méthode effectue certains calculs et renvoie le résultat de ce calcul, vous pouvez évidemment affirmer que le résultat renvoyé est correct.

Si votre code ne renvoie rien, mais qu'il a des effets secondaires, vous pouvez appeler le code puis affirmer que les effets secondaires corrects se sont produits. Ce que les effets secondaires sont déterminera comment vous faites les contrôles.

Dans votre exemple, vous appelez des méthodes statiques à partir de vos fonctions non renvoyées, ce qui complique la tâche à moins de pouvoir vérifier que le résultat de toutes ces méthodes statiques est correct. Un meilleur moyen - du point de vue des tests - consiste à injecter des objets réels dans lesquels vous appelez des méthodes. Vous pouvez ensuite utiliser quelque chose comme EasyMock ou Mockito pour créer un objet fictif dans votre test unitaire et injecter l'objet fictif dans la classe. L'objet simulé vous permet ensuite de vous assurer que les fonctions correctes ont été appelées, avec les valeurs correctes et dans le bon ordre.

Par exemple:

private ErrorFile errorFile;

public void setErrorFile(ErrorFile errorFile) {
    this.errorFile = errorFile;
}

private void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    }
}

Ensuite, dans votre test, vous pouvez écrire:

public void testMethod1() {
    ErrorFile errorFile = EasyMock.createMock(ErrorFile.class);
    errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    EasyMock.expectLastCall(errorFile);
    EasyMock.replay(errorFile);

    ClassToTest classToTest = new ClassToTest();
    classToTest.setErrorFile(errorFile);
    classToTest.method1("a$b");

    EasyMock.verify(errorFile); // This will fail the test if the required addErrorMessage call didn't happen
}
18
Graham

Vous pouvez toujours tester une méthode vide en affirmant qu’elle a eu l’effet secondaire approprié. Dans votre exemple method1, votre test unitaire pourrait ressembler à ceci:

public void checkIfValidElementsWithDollarSign() {
    checkIfValidElement("$",19);
    assert ErrorFile.errorMessages.contains("There is a dollar sign in the specified parameter");
}
4
Jeff Storey

Je pense que vous devriez éviter d'écrire des méthodes ayant des effets secondaires. Renvoie true ou false à partir de votre méthode et vous pouvez vérifier ces méthodes dans des tests unitaires.

2
Garbage

Vous pouvez apprendre quelque chose appelé "moqueur". Vous pouvez utiliser ceci, par exemple, pour vérifier si: - une fonction s'appelait - une fonction s'appelait x fois - une fonction a été appelée au moins x fois - une fonction a été appelée avec un ensemble spécifique de paramètres. Dans votre cas, par exemple, vous pouvez utiliser moqueur pour vérifier que method3 a été appelé une fois avec tout ce que vous transmettez comme arg1 et arg2.

Jetez un coup d'œil à ceux-ci: https://code.google.com/p/mockito/https://code.google.com/p/powermock/

2
Serban Stoenescu

Si votre méthode est nulle et que vous souhaitez rechercher une exception, vous pouvez utiliser expected: https://weblogs.Java.net/blog/johnsmart/archive/2009/09/27/testing-exceptions- junit-47

1
Andreas Hartmann

Si cela est possible dans votre cas, vous pouvez rendre vos méthodes method1(arg1) ... method7() protected au lieu de private afin qu'elles puissent être accessibles depuis la classe de test au sein du même package. Ensuite, vous pouvez simplement tester toutes ces méthodes séparément.

0
martlin