Préférez les tests à l'interface plutôt que les tests sur l'implémentation.
Je crois comprendre que les méthodes privées ne sont pas testables
Cela dépend de votre environnement de développement, voir ci-dessous.
[Les méthodes privées] ne devraient pas être inquiétés, car l'API publique fournira suffisamment d'informations pour vérifier l'intégrité d'un objet.
C'est vrai, TDD se concentre sur le test de l'interface.
Les méthodes privées sont des détails d'implémentation qui peuvent changer au cours d'un cycle de re-factorisation. Il devrait être possible de re-factoriser sans changer l'interface ou le comportement de la boîte noire . En fait, cela fait partie des avantages de TDD, la facilité avec laquelle vous pouvez générer la confiance que les modifications internes à une classe n’affecteront pas les utilisateurs de cette classe.
Eh bien, il est possible pour moi de créer un objet qui n’a que des méthodes privées et qui interagit avec d’autres objets en écoutant leurs événements. Ce serait très encapsulé, mais complètement indestructible.
Même si la classe n'a pas de méthodes publiques, ses gestionnaires d'événements sont son interface publique , et c'est contre cette interface publique que vous pouvez tester.
Étant donné que les événements constituent l'interface, vous devez générer ces événements pour tester cet objet.
Examinez l'utilisation de faux objets comme colle pour votre système de test. Il devrait être possible de créer un objet fictif simple qui génère un événement et enregistre le changement d'état résultant (possible avec un autre objet fictif de récepteur).
En outre, il est considéré comme une mauvaise pratique d’ajouter des méthodes à des fins de test.
Absolument, vous devriez être très prudent d'exposer votre état interne.
Est-ce que cela signifie que TDD est en contradiction avec l'encapsulation? Quel est le bon équilibre?
Absolument pas.
TDD ne devrait pas changer l'implémentation de vos classes autrement que pour les simplifier (en appliquant YAGNI à partir d'un point précédent).
La meilleure pratique avec TDD est identique à la meilleure pratique sans TDD, vous devez simplement savoir pourquoi plus tôt, car vous utilisez l'interface au fur et à mesure que vous la développez.
Je suis enclin à rendre publiques la plupart ou la totalité de mes méthodes ...
Ce serait plutôt jeter le bébé avec l'eau du bain.
Vous ne devriez pas avoir besoin de rendre toutes les méthodes publiques pour pouvoir développer de manière TDD. Voir mes notes ci-dessous pour voir si vos méthodes privées sont vraiment indestructibles.
Un regard plus détaillé sur le test des méthodes privées
Si vous devez absolument tester certains comportements privés d'une classe, en fonction de la langue / de l'environnement, vous pouvez avoir trois options:
- Placez les tests dans la classe que vous souhaitez tester.
- Placez les tests dans un autre fichier source / classe et exposez les méthodes privées que vous souhaitez tester en tant que méthodes publiques.
- Utilisez un environnement de test qui vous permet de garder le code de test et le code de production séparés, tout en autorisant l'accès du code de test aux méthodes privées du code de production.
Évidemment, la 3ème option est de loin la meilleure.
1) Mettez les tests dans la classe que vous souhaitez tester (pas idéal)
Stocker des cas de test dans le même fichier classe / source que le code de production testé est l’option la plus simple. Mais sans beaucoup de directives ou d'annotations pré-processeurs, votre code de test gonfle inutilement votre code de production et, en fonction de la structure de votre code, vous risquez d'exposer accidentellement une implémentation interne à ses utilisateurs.
2) Exposer les méthodes privées que vous voulez tester en tant que méthodes publiques (vraiment pas une bonne idée)
Comme suggéré, cette pratique est très mauvaise, détruit l’encapsulation et exposera l’implémentation interne aux utilisateurs du code.
3) Utiliser un meilleur environnement de test (meilleure option, si disponible)
Dans le monde Eclipse, 3. peut être obtenu en utilisant des fragments . Dans le monde C #, nous pourrions utiliser des classes partielles . Les autres langues / environnements ont souvent des fonctionnalités similaires, il vous suffit de les trouver.
En supposant aveuglément que 1 ou 2 soient les seules options possibles, le logiciel de production serait surchargé de code de test ou d'interfaces de classe désagréables lavant leur linge sale en public. * 8 ')
- Dans l’ensemble, il vaut bien mieux ne pas tester contre une implémentation privée.