Singleton et tests unitaires
L'efficacité de Java a la déclaration suivante sur les tests unitaires des singletons
Rendre une classe singleton peut rendre difficile de tester ses clients, comme il est impossible de substituer un simulacre de mise en œuvre pour un singleton à moins qu'il implémente une interface qui lui sert de type.
Quelqu'un peut-il expliquer pourquoi il en est ainsi ?
- J'utilise les singletons qui sont accessibles à travers l'interface et d'essayer de les rendre apatrides autant que possible. Cela évite beaucoup de problème que les singletons peuvent avoir (mais pas de les utiliser dans de nombreux cas, ils sont souvent utilisés 😉
Vous devez vous connecter pour publier un commentaire.
Vous pouvez utiliser la réflexion pour réinitialiser votre objet singleton pour prévenir les tests de tourmenter les uns les autres.
Ref: tests unitaires-singletons
Se moque nécessitent des interfaces, parce que ce que vous êtes en train de faire est de remplacer le vrai problème sous-jacent avec un imposteur qui imite ce que vous avez besoin pour le test. Depuis le client ne traite que d'une interface de type de référence, il n'a pas besoin de savoir ce que la mise en œuvre est.
Vous ne pouvez pas se moquer d'un béton de classe sans interface, parce que vous ne pouvez pas remplacer le comportement sans que le client de test savoir à ce sujet. C'est une classe entièrement nouvelle dans ce cas.
C'est vrai pour toutes les classes, Singleton ou pas.
Je pense que cela dépend en réalité de la mise en œuvre de la singleton modèle de l'accès.
Par exemple
Peut être très dificile pour tester tout
Ne pas donner aucune information sur le fait que son utilisation d'un singleton. Vous pouvez donc librement remplacer votre usine.
NOTE: un singleton est défini par une seule instance de cette classe dans une application, cependant, la façon dont il est obtenu ou stockée ne doit pas être statique moyens.
C'est tellement simple.
Dans les tests unitaires, vous voulez isoler votre SUT (la classe que vous faites des tests).
Vous ne voulez pas tester un tas de classes, parce que cela irait à l'encontre du but de unité-tests.
Mais pas toutes les classes ne tout sur leur propre, à droite? La plupart des classes d'utilisation autres classes pour faire leur travail, et ils sorte de médiation entre autres classes, et ajouter un peu de leur propre, pour obtenir le résultat final.
Le point est - vous ne se soucient pas comment les classes de votre SUT dépend de travail. Vous vous souciez de la façon dont votre SUT travaille avec les classes. C'est pourquoi vous talon ou se moquer de les classes de votre SUT besoins. Et vous pouvez utiliser ces objets fantaisie parce que vous pouvez les passer en paramètres du constructeur pour votre SUT.
Avec les singletons - la mauvaise chose est que la
getInstance()
méthode est accessible à l'échelle mondiale. Cela signifie que vous avez l'habitude de les appeler à partir de dans une classe, au lieu de selon sur une interface, vous pouvez plus tard se moquer de. C'est pourquoi il est impossible de remplacer quand vous voulez tester votre SUT.La solution est de ne pas utiliser le sournois
public static MySingleton getInstance()
méthode, mais à dépendent sur un interface vos besoins de la classe pour travailler avec. Le faire, et vous pouvez passer en test doubles chaque fois que vous en avez besoin.Le problème n'est pas de tests de singletons eux-mêmes; le livre est à dire que si une classe que vous essayez de tester dépend un singleton, alors vous aurez probablement des problèmes.
À moins que vous (1) faire le singleton implémenter une interface, et (2) injecter le singleton à votre classe à l'aide de cette interface.
Par exemple, les singletons sont généralement instanciée directement comme ceci:
MyClass
peut désormais être très difficile de automatedly test. Par exemple, comme @Boris Pavlovic notes, dans sa réponse, si le singleton est le comportement est basé sur le système de temps, vos tests sont maintenant dépend aussi de l'heure du système, et vous ne pouvez pas être en mesure de tester les cas que, par exemple, dépendent du jour de la semaine.Toutefois, si votre singleton "implémente une interface qui lui sert de type" alors vous pouvez toujours utiliser un singleton mise en œuvre de cette interface, aussi longtemps que vous le transmettre:
Du point de vue de l'essai
MyClass
maintenant, vous ne se soucient pas siSomeSingleton
est singleton ou non: vous pouvez également passer dans toute autre application que vous voulez, y compris le singleton de mise en œuvre, mais plus probablement, vous allez utiliser un simulacre de quelque sorte que vous avez le contrôle de vos tests.BTW, ce n'est PAS la façon de le faire:
Qui fonctionne toujours de la même au moment de l'exécution, mais pour tester vous êtes maintenant encore dépendante de
SomeSingleton
.Singleton objets sont créés, sans contrôle de l'extérieur. Dans l'un des chapitres d'un même livre Bloch suggère d'utiliser
enum
s en tant que par défaut Singleton mise en œuvre. Voyons un exempleDisons que nous avons un code qui doit être exécuté uniquement le week-end:
Tests de loisirs de la méthode va être assez dur. Son exécution va être dépend de la journée, lorsqu'il est exécuté. Si elle s'exécute sur un jour de semaine
doSomeWork()
sera invoquée et le week-endhaveSomeFun()
.Pour ce cas, nous aurions besoin d'utiliser certains outils comme PowerMock pour intercepter le
GregorianCalendar
constructeur, de retour d'une maquette qui sera de retour un index correspondant à un jour de semaine ou de week-end dans les deux cas de test tester à la fois les chemins d'exécution de laleisure
méthode.Ce n'est pas vrai. Vous pouvez sous-classe votre singleton et de définition d'injecter un simulacre. Alternativement, vous pouvez utiliser PowerMock de se moquer des méthodes statiques. Toutefois, la nécessité de se moquer des singletons peuvent être symptomatique d'une mauvaise conception.
Le vrai problème est Singletons quand abusé transformer en dépendance aimants. Depuis qu'ils sont accessibles de partout, il peut apparaissent plus commode de mettre les fonctions dont vous avez besoin, plutôt que de déléguer à une classe appropriée, en particulier pour les programmeurs de nouveau à la programmation orientée objet.
La testabilité problème est maintenant vous avez un tas de Singletons qui sont accessibles par votre objet sous test. Même si l'objet est probablement utilise seulement une petite fraction de méthodes dans les Singletons, vous avez encore besoin de se moquer les uns des Singleton et de comprendre les méthodes qui sont en dépendait. Les Singletons avec un état statique (Monostate modèle) sont encore pire, car vous pouvez avoir à comprendre que les interactions entre les objets sont affectés par le Singleton de l'état.
Utilisé avec soin, les Singletons et la testabilité peut se produire ensemble. Par exemple, en l'absence de DI framework, vous pouvez utiliser les Singletons que vos Usines et ServiceLocators, que vous pouvez setter injecter pour créer une fausse couche de service pour votre bout-à-bout tests.
Il est possible, voir l'exemple
Autant que je sache, d'une classe implémentant un Singleton ne peut pas être prolongé (constructeur de la superclasse est toujours appelé implicitement et le constructeur dans un Singleton est privé). Si vous voulez simuler une classe, vous devez étendre la classe. Comme vous le voyez, dans ce cas, il ne serait pas possible.
Le problème avec les singletons (et aussi avec des méthodes statiques), c'est qu'il rend difficile pour remplacer le code avec un moqué de mise en œuvre.
Par exemple, considérons le code suivant
Il n'est pas facile d'écrire un test unitaire pour la méthode foo et de vérifier le bon comportement est effectuée.
C'est parce que vous ne pouvez pas facilement changer la valeur de retour de
getFeatureFlag
.Le même problème existe pour les méthodes statiques - il n'est pas facile de remplacer la cible réelle méthode de la classe avec une simulation de comportement.
Bien sûr, il existe des solutions de contournement comme powermock, ou l'injection de dépendance à la méthode, ou la réflexion dans les tests.
Mais il est beaucoup mieux de ne pas utiliser les singletons, en premier lieu,