12
votes

Tester avec fil.sleep

Quelles sont les approches recommandées pour utiliser thread.sleep () pour accélérer les tests.

Je teste une bibliothèque de réseau avec une fonctionnalité de nouvelle tentative lorsque les connexions sont supprimées ou des erreurs de délai d'attente, etc. Cependant, la bibliothèque utilise un thread.sleep () entre les tentatives (donc il gagnait " t Connectez des milliers fois pendant que le serveur redémarre). L'appel ralentit considérablement les tests de l'unité et je me demande quelles sont les options pour le remplacer.

Remarque, je suis ouvert pour changer le code ou utiliser un cadre moqueur pour simuler le fil.sleep (), mais j'aimerais entendre d'abord vos opinions / recommandation.


2 commentaires

Cela pourrait être considéré comme une étude de cas pour les tests unitaires avec la moqueur


N'utilisez pas de thread.sleep (), utilisez une approche d'attente (). Thread.sleep () utilise des cycles de processeur, tout en attente () ne le fait pas.


6 Réponses :


3
votes

Faites le temps de sommeil configurable via un setter et fournissez une valeur par défaut. Donc, dans vos tests de l'unité, appelez le Setter avec un petit argument (1 par exemple), puis exécutez la méthode qui appellerait thread.sleep () . .

Une autre approche similaire consiste à rendre si configurable via un booléen, de sorte que thread.sleep () ne s'appelle pas du tout si le booléen est défini sur faux .


1 commentaires

Et si je ne veux pas exposer mes configurations internes à l'extérieur uniquement pour les tests?



2
votes

Créez un type de délai de réessayer qui représente la stratégie pour les retards de réessayage. Invoquez une méthode sur le type de stratégie pour le retard. Moquez-le comme vous voulez. Pas de logique conditionnelle ou true code> / false code> drapeaux. Il suffit d'injecter le type que vous voulez.

dans ConnecTryPolicy.java p> xxx pré>

dans sle sleepconnecetrypolicy.java p> xxx pré>

MockConnecretrypolicy.java P>

public final class MockConnectRetryPolicy implements ConnectRetryPolicy {    
    @Override
    public void doRetryDelay() {
        // no delay
    }
}


1 commentaires

Ce n'est pas simplement une politique, mais un exécuteur de sommeil configurable. Une politique ne représenterait que la stratégie autour de dormir, ne pas l'exécuter. Pour le reste, une idée sonore.



14
votes

C'est généralement une bonne idée de déléguer une fonctionnalité liée au temps à un composant séparé. Cela inclut l'obtention de l'heure actuelle, ainsi que des retards comme Whle.sleep (). De cette façon, il est facile de remplacer ce composant avec une simulacre pendant les tests, ainsi que de passer à une implémentation différente.


3 commentaires

J'ai été tenté de créer une classe à résumé tout cela.


Marche à suivre. De cette façon, vous pouvez également définir votre configuration ou même ignorer tout ce que vous voulez dans un seul endroit, puis diffusant ce creux logique.


@notnoop exactement ce que j'ai fait avec une classe horloge . Prend en charge les opérations de base telles que clock.now () , clock.freeze () , clock.frez (Pointintime) et ainsi de suite. Aucun composant n'interagit avec le temps d'exécution directement pour aller chercher du temps, mais plutôt passer par horloge .



1
votes

Eugene a raison, faites votre propre composant pour envelopper le système hors de votre contrôle, je ne suis que je pensais que je pensais que je partageais, c'est appelé ' auto-twunt 'Vérifiez ceci:

générateur code> est une classe qui, lorsque vous appelez getid () code> it Renvoie l'heure actuelle du système. P>

public interface SystemTime {

    long currentTimeMillis();

}


0 commentaires

2
votes

Je dirais pourquoi essayez-vous de tester le thread.sleep. Il semble que ce soit moi, vous essayez de tester le comportement comme une conséquence d'un événement.

I.e. Que se passe-t-il si:

  • Délai de connexion
  • connexion déposée

    Si vous modélisez le code basé sur des événements, vous pouvez tester ce que devrait se produire si un événement particulier s'est produit plutôt que d'avoir à proposer une construction qui masque les appels d'API simultanés. Sinon qu'est-ce que tu tests vraiment? Est-ce que vous testez la manière dont votre application réagit à différents stimuli ou simplement à tester la JVM fonctionne correctement?

    Je suis d'accord avec les autres lecteurs qui, parfois, il est utile de mettre une abstraction autour de n'importe quel moment de code ou de thread lié à une horloge virtuelle http://c2.com/cgi/wiki?virtualclock afin que vous puissiez vous moquer de tout comportement de synchronisation / simultané et concentrez-vous sur le comportement de l'unité elle-même.

    Il semble également que vous puissiez adopter un modèle d'état afin que votre objet a un comportement spécifique en fonction de l'état de l'état. I.e attenteConnectiondstate, ConnectionDroppedstate. La transition vers différents états serait via les différents événements, c'est-à-dire un délai d'attente, une connexion abandonnée, etc. Vous ne savez pas si cela surtout pour vos besoins, mais cela supprime certainement beaucoup de logique conditionnelle pouvant rendre le code plus compliqué et peu clair.

    Si vous approchez de cette façon, vous pouvez toujours tester le comportement au niveau de l'unité tout en effectuant des tests toujours in situ avec un test d'intégration ou un test d'acceptation ultérieurement.


0 commentaires

6
votes

Je viens de faire face à un problème similaire et j'ai créé une interface code> code> à l'abstraction de ce type:

assertThat( new DateTime( DateTimeUtils.currentTimeMillis() ) ).isEqualTo( new DateTime( "2014-03-27T00:00:30" ) );


0 commentaires