J'ai quelques méthodes qui devraient faire appel System.exit()
à certaines entrées. Malheureusement, le test de ces cas entraîne l'arrêt de JUnit! Placer les appels de méthode dans un nouveau thread ne semble pas aider, car System.exit()
met fin à la JVM, pas seulement au thread actuel. Existe-t-il des schémas communs pour gérer cela? Par exemple, puis-je remplacer un talon pour System.exit()
?
[EDIT] La classe en question est en fait un outil en ligne de commande que j'essaie de tester dans JUnit. Peut-être que JUnit n'est tout simplement pas le bon outil pour le travail? Les suggestions d'outils de test de régression complémentaires sont les bienvenues (de préférence quelque chose qui s'intègre bien avec JUnit et EclEmma).
java
multithreading
unit-testing
junit
testability
Chris Conway
la source
la source
System.exit()
c'est mauvais - votre programme devrait échouer rapidement. Le fait de lever une exception prolonge simplement une application dans un état non valide dans les situations où un développeur souhaite quitter et donnera de fausses erreurs.Réponses:
En effet, Derkeiler.com propose:
System.exit()
?System.exit()
de quitter réellement la JVM:Mise à jour de décembre 2012:
Will propose dans les commentaires à l' aide de System Rules , une collection de règles JUnit (4.9+) pour tester le code qui utilise
java.lang.System
.Cela a été initialement mentionné par Stefan Birkner dans sa réponse de décembre 2011.
Par exemple:
la source
System.exit
chaque fois qu'un argument de ligne de commande non valide est fourni.La bibliothèque System Lambda a une méthode.
catchSystemExit
Avec cette règle vous pouvez tester le code, qui appelle System.exit (...):Pour Java 5 à 7, les règles système de la bibliothèque ont une règle JUnit appelée ExpectedSystemExit. Avec cette règle, vous pouvez tester le code qui appelle System.exit (...):
Divulgation complète: je suis l'auteur des deux bibliothèques.
la source
ExpectedSystemRule
est bien sûr agréable; le problème est qu'il nécessite une bibliothèque tierce supplémentaire qui fournit très peu en termes d'utilité dans le monde réel et est spécifique à JUnit.exit.checkAssertionAfterwards()
.Que diriez-vous d'injecter un "ExitManager" dans ces méthodes:
Le code de production utilise ExitManagerImpl et le code de test utilise ExitManagerMock et peut vérifier si exit () a été appelé et avec quel code de sortie.
la source
Vous pouvez réellement vous moquer ou
System.exit
méthode, dans un test JUnit.Par exemple, en utilisant JMockit, vous pourriez écrire (il existe également d'autres moyens):
EDIT: Test alternatif (utilisant la dernière API JMockit) qui ne permet à aucun code de s'exécuter après un appel à
System.exit(n)
:la source
exit
appel (pas que c'était vraiment un problème, OMI).Runtime
peut être moquée, mais ne s'arrête pasSystem.exit
au moins dans mon scénario exécutant des tests dans Gradle.Une astuce que nous avons utilisée dans notre base de code était d'avoir l'appel à System.exit () être encapsulé dans un implément Runnable, que la méthode en question utilisé par défaut. Pour le test unitaire, nous avons défini un Runnable simulé différent. Quelque chose comme ça:
... et la méthode de test JUnit ...
la source
Créez une classe factice qui enveloppe System.exit ()
Je suis d'accord avec EricSchaefer . Mais si vous utilisez un bon cadre moqueur comme Mockito une simple classe concrète suffit, pas besoin d'une interface et de deux implémentations.
Arrêt de l'exécution des tests sur System.exit ()
Problème:
Un simulé
Sytem.exit()
ne mettra pas fin à l'exécution. C'est mauvais si vous voulez tester quithing2
n'est pas exécuté.Solution:
Vous devriez refactoriser ce code comme suggéré par Martin :
Et faites
System.exit(status)
dans la fonction d'appel. Cela vous oblige à avoir tous vosSystem.exit()
s en un seul endroit dans ou à proximitémain()
. C'est plus propre que d'appelerSystem.exit()
profondément dans votre logique.Code
Wrapper:
Principale:
Tester:
la source
J'aime certaines des réponses déjà données, mais je voulais démontrer une technique différente qui est souvent utile lors de la mise à l'essai du code hérité. Étant donné le code comme:
Vous pouvez effectuer une refactorisation sûre pour créer une méthode qui encapsule l'appel System.exit:
Ensuite, vous pouvez créer un faux pour votre test qui remplace la sortie:
Il s'agit d'une technique générique pour substituer le comportement aux cas de test, et je l'utilise tout le temps lors de la refactorisation du code hérité. Ce n'est généralement pas là où je vais laisser quelque chose, mais une étape intermédiaire pour tester le code existant.
la source
Un rapide coup d'œil à l'API, montre que System.exit peut lever une exception esp. si un gestionnaire de sécurité interdit l'arrêt du VM. Une solution serait peut-être d'installer un tel gestionnaire.
la source
Vous pouvez utiliser le java SecurityManager pour empêcher le thread actuel d'arrêter la machine virtuelle Java. Le code suivant devrait faire ce que vous voulez:
la source
Pour que la réponse de VonC s'exécute sur JUnit 4, j'ai modifié le code comme suit
la source
Vous pouvez tester System.exit (..) en remplaçant l'instance Runtime. Par exemple avec TestNG + Mockito:
la source
Il existe des environnements où le code de sortie renvoyé est utilisé par le programme appelant (tel que ERRORLEVEL dans MS Batch). Nous avons des tests sur les principales méthodes qui le font dans notre code, et notre approche a été d'utiliser un remplacement SecurityManager similaire à celui utilisé dans d'autres tests ici.
Hier soir, j'ai monté un petit JAR en utilisant les annotations Junit @Rule pour masquer le code du gestionnaire de sécurité, ainsi que pour ajouter des attentes basées sur le code de retour attendu. http://code.google.com/p/junitsystemrules/
la source
La plupart des solutions
System.exit()
est appeléSecurityManager
Ainsi, la plupart des solutions ne conviennent pas aux situations où:
System.exit()
assertAll()
, par exemple.Je n'étais pas satisfait des restrictions imposées par les solutions existantes présentées dans les autres réponses, et j'ai donc trouvé quelque chose par moi-même.
La classe suivante fournit une méthode
assertExits(int expectedStatus, Executable executable)
qui affirme qu'elleSystem.exit()
est appelée avec un spécifiéstatus
valeur et le test peut continuer après. Cela fonctionne de la même manière que JUnit 5assertThrows
. Il respecte également un gestionnaire de sécurité existant.Il reste un problème: lorsque le code sous test installe un nouveau gestionnaire de sécurité qui remplace complètement le gestionnaire de sécurité défini par le test. Toutes les autres
SecurityManager
solutions à ma connaissance connaissent le même problème.Vous pouvez utiliser la classe comme ceci:
Le code peut facilement être porté sur JUnit 4, TestNG ou tout autre framework, si nécessaire. Le seul élément spécifique au framework échoue au test. Cela peut facilement être changé en quelque chose d'indépendant du framework (autre qu'un Junit 4
Rule
Il y a place à amélioration, par exemple, la surcharge
assertExits()
de messages personnalisables.la source
Permet
Runtime.exec(String command)
de démarrer la JVM dans un processus distinct.la source
Il y a un problème mineur avec la
SecurityManager
solution. Certaines méthodes, telles queJFrame.exitOnClose
, appellent égalementSecurityManager.checkExit
. Dans mon application, je ne voulais pas que cet appel échoue, j'ai donc utiliséla source
Appeler System.exit () est une mauvaise pratique, sauf si cela se fait à l'intérieur d'un main (). Ces méthodes devraient lever une exception qui, finalement, est interceptée par votre main (), qui appelle ensuite System.exit avec le code approprié.
la source