Je suis déchiré entre l'utilisation des classes utilitaires DI et statiques sur mon code.
J'ai actuellement créé une classe statique DateUtil qui est uniquement destinée à être accessible de manière statique. Cette classe est chargée de simplement créer et manipuler des dates en utilisant une variété de bibliothèques sans aucune dépendance externe tierce.
Tout semble bien mais maintenant les tests unitaires deviennent plus compliqués puisque maintenant nous devons utiliser PowerMockito pour bloquer correctement le comportement de la classe statique.
Au contraire, si j'ai supprimé la statique de DateUtil et l'ai convertie en Spring @Component, alors maintenant les tests unitaires peuvent être un peu plus faciles, cependant, maintenant nous avons toutes ces dépendances partout et je ne suis pas sûr que cela est le but des haricots gérés par Spring.
Comment dois-je procéder? Est-il acceptable d'utiliser des beans Spring partout et d'oublier complètement le code statique? Peut-on abuser des capacités DI de Spring? Quand est-ce "trop DI"?
L'hypothèse dominante selon laquelle les méthodes statiques ne sont pas testables par unité semble provenir du fait que les développeurs sont habitués à écrire des tests unitaires sur des instances de classe instanciables, et toutes les choses qui vont avec, comme les simulations, les stubs, les interfaces, l'injection de dépendance, etc. ne peut rien faire de tout cela avec des classes statiques. Cependant ...
Les méthodes statiques fonctionnant sur (plus ou moins) des types primitifs comme Date ne nécessitent rien de tout cela. En supposant que vos méthodes statiques sont pures (c'est-à-dire qu'elles ne contiennent aucun effet secondaire et évitent l'état statique), vous pouvez les tester en les appelant simplement avec une valeur de test et en affirmant le résultat de retour correct.
C'est ça. Faire autre chose va noyer vos collègues programmeurs dans une mer de complexité inutile sans aucun avantage supplémentaire.
Les classes non statiques ont un objectif très spécifique. Si vous en avez besoin, utilisez-en un. Mais si vous n'en avez pas besoin, pourquoi l'utiliser si votre seule justification est que vous ne pouvez pas appliquer vos techniques de test de classe habituelles? Le remède à cela est d'apprendre une technique de test plus appropriée, pas de chausse-pied votre méthode testée dans une classe simplement parce que vous pensez avoir besoin d'un conteneur pour le tester.
Lectures complémentaires
Est-ce que l'électricité statique est universellement "mauvaise" pour les tests unitaires et si oui, pourquoi Resharper le recommande-t-il?
Voici ma règle d'or. Utilisez des classes utilitaires statiques si les méthodes ne comportent que 1 à 2 lignes et effectuez des opérations faciles à nommer avec juste un mot ou deux, et qui ne changeront probablement jamais. Ainsi, par exemple, Math.max(double, double)
constitue une excellente méthode d'utilité statique, tout comme MoreObjects.firstNonNull(Object...)
.
Étant donné qu'il est très peu probable que la définition de ce que font ces méthodes change, il est également correct de prendre en compte leur comportement lors du test d'autres classes qui utilisent ces méthodes. Si vous testez votre méthode qui utilise Math.max()
, vous n'essayez pas de bloquer le comportement de Math.max()
, n'est-ce pas? On pourrait dire que de cette façon, votre test n'est pas vraiment un test unitaire, mais peu importe. Si votre méthode utilise une méthode de classe String
, essayez-vous de bloquer ce comportement? Cela n'aurait aucun sens.
Si les critères ci-dessus ne sont pas remplis, je préfère une DI normale. Ainsi, dans le cas des dates, si les opérations sont quelque chose comme firstMondayAfter(Date)
, une classe d'utilité statique devrait être complètement correcte. Si c'était plus comme getStartOfMyCompanyFiscalYear(Date)
, j'irais avec DI.