18 votes

JUnit termine les threads enfants

Lorsque je teste l'exécution d'une méthode qui crée un thread enfant, le test JUnit se termine avant le thread enfant et le tue.

Comment puis-je forcer JUnit à attendre que le thread enfant termine son exécution ?

8voto

Eyal Schneider Points 11399

Après avoir lu la question et certains commentaires, il semble que ce dont vous avez besoin soit une technique de test unitaire des opérations asynchrones . doSomething() renvoie immédiatement, mais vous voulez que le code de test attende son achèvement, puis effectue quelques validations.

Le problème est que le test n'est pas conscient des threads créés par l'appel, il n'a donc apparemment aucun moyen de les attendre. On peut penser à de nombreuses façons sophistiquées (et probablement imparfaites) de résoudre ce problème, mais à mon avis, il y a un problème de conception ici. Un test unitaire doit simuler un client d'une API et ne doit rien présumer de l'implémentation ; il doit seulement tester la fonctionnalité, telle que reflétée par l'API et sa documentation. Par conséquent, j'éviterais d'essayer de détecter et de suivre les threads créés par l'appel asynchrone. Au lieu de cela, j'améliorerais l'API de la classe testée, si nécessaire. La classe à laquelle appartient l'appel asynchrone devrait fournir un mécanisme de détection de la terminaison. Je peux penser à 3 façons, mais il y en a probablement d'autres :

  1. Permet d'enregistrer un écouteur qui sera notifié une fois l'opération terminée.

  2. Fournir une version synchrone de l'opération. L'implémentation peut appeler la version asynchrone, puis bloquer jusqu'à la fin. Si la classe ne doit pas exposer une telle méthode, sa visibilité peut être réduite à package protected, afin que le test puisse y accéder.

  3. En utilisant le modèle d'attente et de notification, sur un objet visible.

Si la classe ne fournit pas un tel mécanisme, alors elle n'est pas vraiment testable, et pire, elle n'est probablement pas très réutilisable non plus.

2voto

Chris Dennett Points 12396

Essayez d'utiliser [thread.join()](https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()) sur le fil de discussion créé. Cela attendra que ce thread meure.

Edit : pour éviter cela, essayez Thread.getThreadGroup().setDaemon(true); dans le test, ou peut-être dans le setUp() méthode. Je ne l'ai pas testé cependant.

Un groupe de threads de démon est automatiquement détruit lorsque son dernier thread est arrêté ou que son dernier groupe de threads est détruit.

Je me demande si JUnit appelle System.exit() ou autre chose dès que le test est terminé, cependant.

1voto

Jonathan Points 875

La technique de base que @Eyal a décrite est ce que ConcurrentUnit est destiné. L'usage général est le suivant :

  1. Créer des fils de discussion
  2. Faire attendre ou dormir le fil principal
  3. Effectuer des assertions à partir des threads de travail (qui, via ConcurrentUnit, sont rapportées au thread principal).
  4. Reprendre le fil principal à partir d'un des fils de travail une fois que toutes les assertions sont terminées.

Voir la page ConcurrentUnit pour plus d'informations.

0voto

Istao Points 2764

Peut-être que vous pouvez regrouper vos fils avec un ExecutorService puis utiliser arrêt et awaitTermination méthode ?

La condition est d'utiliser Runnable ou Future, pas les Threads eux-mêmes.

0voto

Fred Points 1
        while (s.isRunning()) {
            try {
                Thread.sleep(SLEEP_TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

Vous pouvez essayer de bloquer le thread de JUnit et lui demander d'attendre que votre thread soit terminé. Le site Thread.sleep() est nécessaire pour que votre fil ne monopolise pas le CPU. Dans cet exemple, s serait votre thread, vous aurez besoin d'une fonction isRunning() afin de pouvoir vérifier si le thread est toujours en cours d'exécution à chaque fois que la méthode SLEEP_TIME millisecondes. Je sais que ce n'est pas la meilleure solution, mais si vous n'avez que 2 fils et que vous ne voulez pas que JUnit tue votre fil, cela fonctionne. La boucle while permet à ce thread JUnit de rester en vie et d'attendre que l'autre thread se termine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X