[JAVA] Pratiques de test basées sur Dagger Hilt

Ce document sur Dagger Hilt, une bibliothèque DI recommandée par Google pour le développement Android (disponible dans le langage JVM). https://dagger.dev/hilt/testing-philosophy J'ai personnellement essayé un très bon test, alors je vais l'écrire. Aussi, j'ai l'impression que vous pouvez voir les bons points de Hilt autres que la partie simple.


Il décrit les pratiques de test basées sur Dagger Hilt. Les API et les fonctionnalités de Dagger Hilt reposent sur la philosophie implicite de ce qui fait de bons tests. Cependant, les bons tests ne sont pas acceptés par tout le monde, c'est donc un document pour clarifier la philosophie des tests dans l'équipe Hilt.

Que tester

Hilt recommande des «** tests externes du point de vue de l'utilisateur **». Les utilisateurs externes ont beaucoup de sens. Il fait référence à de vrais utilisateurs, ainsi qu'aux utilisateurs de classes et d'API. Le point important est que "n'exprimez pas les détails de l'implémentation". L'écriture de tests qui dépendent d'implémentations internes, comme des tests qui dépendent de méthodes internes, rend les tests fragiles. ** Si le nom de la méthode interne change, un bon test n'a pas besoin de changer quoi que ce soit. Le seul facteur qui rompt le test en cours est lorsqu'il y a des changements visibles par l'utilisateur. ** **

Tirez parti des dépendances réelles

** La philosophie de test de Hilt n'oblige pas chaque classe à écrire un test individuellement. En réalité, de telles règles violent le principe du "test du point de vue de l'utilisateur". ** Gardez le test aussi petit que nécessaire pour le rendre plus facile à écrire et à exécuter. (Rapide, ne consomme pas beaucoup de ressources, etc.) S'il n'y a pas d'autre différence, ** le test priorise les éléments suivants dans cet ordre **

Cependant, il y a un compromis à faire.

Hilt résout le premier problème. (Détails ci-dessous) Les performances peuvent être un problème, mais dans la plupart des cas, ce n'est pas le cas. Cela ne peut poser problème que s'il existe des dépendances d'E / S. S'il est pratique et robuste de tirer parti de dépendances réelles sans compromettre significativement les performances, alors des dépendances réelles doivent être utilisées. Si cela a un impact négatif significatif sur le test, Hilt fournit un moyen de remplacer la fixation.

Grand avantage d'utiliser plus de dépendances réelles

Si vous ne pouvez pas utiliser les vraies dépendances, utilisez le Fake standard fourni par la bibliothèque. Standard Fake est meilleur que Mock s'il est maintenu par l'auteur de la bibliothèque ou en bénéficiant d'une couverture robuste. Pour ces raisons ** Mock est un dernier recours **.

Poignée, DI et test

Avec ces fondations, nous entrons dans "Hilt, DI, and Test". ** La réponse de Dagger Hilt à "utiliser des dépendances réelles" est d'utiliser DI / Dagger dans Test **. C'est plus proche de la réalité, car les objets sont créés pour être réalisés en production. Cela signifie que les tests sont moins fragiles que le code de production, ce qui rend les objets réels plus faciles à utiliser. En fait, si vous avez un constructeur @ Inject, il est plus facile et moins de code d'utiliser Dagger que de créer un Mock.

Malheureusement, faire un tel test sans poignée a été difficile jusqu'à présent en raison du travail de mise en place de la plaque chauffante et de la dague. Mais Hilt peut générer un code de plaque de chaudière et configurer différents paramètres pour les tests lorsque Fake ou Mock est nécessaire. Avec Hilt, ce problème ne vous empêche pas d'écrire des tests dans Dagger et vous pouvez facilement tirer parti des dépendances réelles.

Voici comment Hilt remplace les dépendances par Test. https://qiita.com/takahirom/items/3231edf2a430569b3e9d#testing

Inconvénients des autres solutions

La méthode consistant à ne pas utiliser Dagger dans le test unitaire est une méthode très courante. Cela présente malheureusement un inconvénient majeur, mais il est compréhensible étant donné la difficulté d'utiliser Dagger sans Hilt. Par exemple, essayez de tester la classe Foo.

class Foo @Inject constructor(bar: Bar) {
}

Si vous n'utilisez pas Dagger dans ce cas, appelez simplement le constructeur. À première vue, c'est très simple et compréhensible, mais cela commence à s'effondrer lorsque vous commencez à adapter Bar au constructeur de Foo.

L'instanciation directe dans les tests facilite l'utilisation de Mock

Vous devriez utiliser la vraie classe Bar autant que possible en "utilisant de vraies dépendances" dont j'ai parlé plus tôt. Mais que dois-je faire? Pour utiliser la classe Foo dans un test, il s'agit en fait d'une récurrence: vous devez l'instancier vous-même, vous devez donc également instancier ** Bar, ainsi que si vous avez une dépendance sur Bar. Vous devez les instancier. Pour éviter de devenir trop profond, vous devez commencer à utiliser Fake and Mock, non pas à cause de la vitesse ou des performances du test, mais parce que de nombreux cordons de plaque de chaudière fragiles posent des problèmes de maintenance. Ce n'est pas une bonne raison de commencer à utiliser Fake ou Mock. Et maintenant je suis obligé de faire ça. ** ** Comme indiqué précédemment, la méthode Fake standard peut réduire la charge de maintenance de l'instanciation directe. Mais ce n'est pas toujours simple. (Omis: De même, FakeBar dépend de l'horloge, etc. Fake doit également gérer les dépendances.)

Cela encourage généralement les développeurs à utiliser Mock. ** Mock résout le problème du chaînage des dépendances, mais a le sérieux inconvénient d'être discrètement laissé pour compte ou de rendre les tests inutiles dans le but global de trouver de vrais bogues. ** Étant donné que personne d'autre que le créateur du test ne vérifie le fonctionnement de Mock, il est fort possible que le test ne teste pas des scénarios utiles au fil du temps.

L'instanciation directe dans les tests représente les détails de l'implémentation

** L'instanciation directe rompt la pratique de «ne pas représenter les détails d'implémentation». Parce que pour appeler le constructeur des détails de la dépendance **. Si la barre a @Inject construcotr, vous n'avez pas besoin de savoir qu'elle dépend de la barre car Foo peut refactoriser les détails d'implémentation. Pour expliquer ce point, lorsque Foo a une dépendance telle que Bar ou Baz comme Foo (Bar, Baz), rien ne se passe dans Dagger même si l'ordre de ce paramètre est modifié. Cependant, si vous l'avez instancié directement, vous devez modifier le test. De même, l'ajout d'une nouvelle @Inject class ou d'une liaison facultative n'a pas besoin d'être modifiée en production, mais elle devra être modifiée lors des tests.

Résumé

Hilt est conçu pour remédier aux inconvénients de l'utilisation de Hilt dans les tests de Dagger afin de faciliter l'écriture de tests avec des dépendances réelles. Tester avec Hilt est généralement une bonne expérience si vous suivez ces principes.

Recommended Posts

Pratiques de test basées sur Dagger Hilt
Dagger Hilt (document DevFest 2020)