Parfois, les fonctions privées d'un module ou d'une classe sont simplement des unités de fonctionnalité internes à extraire, qui pourraient mériter leurs propres tests. Alors pourquoi ne pas les tester? Nous allons écrire des tests pour eux plus tard si / quand ils sont extraits. Alors pourquoi ne pas écrire les tests maintenant, alors qu'ils font toujours partie du même fichier?
Démontrer:
J'ai d'abord écrit module_a
. Maintenant, je veux écrire des tests pour cela. Je voudrais tester la fonction "privée" _private_func
. Je ne comprends pas pourquoi je n'écrirais pas de test pour cela, si plus tard je pouvais le refactoriser dans son propre module interne de toute façon, puis écrire des tests pour cela.
Supposons que j'ai un module avec les fonctions suivantes (il pourrait également s'agir d'une classe):
def public_func(a):
b = _do_stuff(a)
return _do_more_stuff(b)
_do_stuff
et _do_more_stuff
sont des fonctions «privées» du module.
Je comprends l'idée que nous devrions uniquement tester l'interface publique, pas les détails de mise en œuvre. Cependant, voici la chose:
_do_stuff
et _do_more_stuff
contiennent la majorité des fonctionnalités du module. Chacun d'eux pourrait être une fonction publique d'un module «interne» différent. Mais ils ne sont pas encore évolués et suffisamment volumineux pour être extraits dans des fichiers séparés.
Il est donc judicieux de tester ces fonctions, car ce sont des unités de fonctionnalité importantes. S'ils étaient dans différents modules en tant que fonctions publiques, nous les aurions testés. Alors pourquoi ne pas les tester lorsqu'ils ne sont pas encore (ou jamais) extraits dans un fichier différent?
Réponses:
Le besoin de tester n'est pas le même que le besoin d'être public.
Le code non trivial doit être testé indépendamment de l'exposition. Le comportement non public n'a pas besoin d'exister et encore moins d'être testé.
Ces vues contradictoires peuvent vous conduire à vouloir rendre chaque fonction publique ou à refuser de prendre en compte le code dans une fonction à moins qu'elle ne soit publique.
Ce n'est pas la réponse. Soyez prêt à créer des fonctions d'assistance privées. Testez-les via l'interface publique qui l'utilise le plus possible.
Si le test via l'interface publique n'exerce pas suffisamment la fonction privée, la fonction privée essaie de permettre beaucoup.
La validation peut aider à restreindre ce que permet la fonction privée. Si vous ne pouvez pas passer un null en passant par l'interface publique, vous pouvez toujours lever une exception si une passe de toute façon.
Pourquoi devrais-tu? Pourquoi tester ce que vous ne verrez jamais? Parce que les choses changent. Il peut être privé maintenant mais public plus tard. Le code d'appel pourrait changer. Le code qui rejette explicitement null rend l'utilisation correcte et l'état attendu clairs.
Bien sûr, null pourrait être bien. Ce n'est qu'un exemple ici. Mais si vous attendez quelque chose, il est utile de clarifier cette attente.
Ce n'est peut-être pas le genre de test que vous aviez en tête, mais j'espère que vous serez prêt à créer des fonctions d'assistance privées le cas échéant.
L'envie de tester est bonne mais ne doit pas être le moteur de la conception de votre API publique. Concevez l'API publique pour qu'elle soit facile à utiliser. Ce ne sera probablement pas le cas si toutes les fonctions sont publiques. L'API doit être quelque chose que les gens peuvent comprendre comment utiliser sans plonger dans le code. Ne laissez pas ces personnes se demander à quoi sert cette fonction d'aide étrange.
Masquer les fonctions d'assistance publique dans un module interne est une tentative de respecter la nécessité d'une API propre tout en exposant les assistants pour les tests. Je ne dirai pas que c'est faux. Vous pourriez faire le premier pas vers une couche architecturale différente. Mais s'il vous plaît, maîtrisez l'art de tester les fonctions d'assistance privées à travers les fonctions publiques qui les utilisent en premier. De cette façon, vous n'utiliserez pas trop cette solution de contournement.
la source
Réponse courte: Non
Réponse plus longue: oui, mais via l'API publique de votre classe
L'idée générale des membres privés d'une classe est qu'ils représentent des fonctionnalités qui devraient être invisibles en dehors de l '«unité» de code, quelle que soit la taille de votre choix. Dans le code orienté objet, cette unité finit souvent par être une classe.
Votre classe doit être conçue de telle sorte qu'il soit possible d'invoquer toutes les fonctionnalités privées via différentes combinaisons d'état d'entrée. Si vous trouvez qu'il n'y a pas de façon relativement simple de le faire, il est probable que votre conception nécessite une attention particulière.
Après clarification de la question, ce n'est qu'une question de sémantique. Si le code en question peut fonctionner comme une unité autonome distincte et est testé comme s'il s'agissait d'un code public, je ne vois aucun avantage à ne pas le déplacer dans un module autonome. À l'heure actuelle, cela ne sert qu'à confondre les futurs développeurs (y compris vous-même, dans 6 mois), à savoir pourquoi le code apparemment public est caché dans un autre module.
la source
L'intérêt des fonctions privées est qu'elles sont des détails d'implémentation cachés qui peuvent être modifiés à volonté, sans changer l'API publique. Pour votre exemple de code:
Si vous avez une série de tests qui n'utilisent que
public_func
, alors si vous le réécrivez à:alors, tant que le résultat de retour pour une valeur particulière de
a
reste le même, alors tous vos tests seront bons. Si le résultat de retour change, un test échouera, soulignant le fait que quelque chose s'est cassé.C'est une bonne chose: API publique statique; fonctionnement interne bien encapsulé; et des tests robustes.
Cependant, si vous aviez écrit des tests pour
_do_stuff
ou_do_more_stuff
puis effectué la modification ci-dessus, vous auriez maintenant un tas de tests cassés, non pas parce que la fonctionnalité a changé, mais parce que l'implémentation de cette fonctionnalité a changé. Ces tests devraient être réécrits pour fonctionner avec les nouvelles fonctions, mais après les avoir fait fonctionner, tout ce que vous savez, c'est que ces tests ont fonctionné avec les nouvelles fonctions. Vous auriez perdu les tests d'origine et ne sauriez donc pas si le comportement depublic_func
a changé et vos tests seraient donc inutiles.C'est une mauvaise chose: une API changeante; fonctionnement interne exposé étroitement couplé aux tests; et des tests fragiles qui changent dès que des modifications sont apportées à l'implémentation.
Donc non, ne testez pas les fonctions privées. Déjà.
la source