J'ai une implémentation squelettique, comme dans l'article 18 de Effective Java (discussion approfondie ici ). C'est une classe abstraite qui fournit 2 méthodes publiques methodA () et methodB () qui appellent des méthodes de sous-classes pour "combler les lacunes" que je ne peux pas définir de manière abstraite.
Je l'ai d'abord développé en créant une classe concrète et en écrivant des tests unitaires. Lorsque la deuxième classe est arrivée, j'ai pu extraire des comportements communs, implémenter les "lacunes manquantes" dans la deuxième classe et c'était prêt (bien sûr, les tests unitaires ont été créés pour la deuxième sous-classe).
Le temps a passé et maintenant j'ai 4 sous-classes, chacune implémentant 3 méthodes protégées courtes qui sont très spécifiques à leur implémentation concrète, tandis que l'implémentation squelettique fait tout le travail générique.
Mon problème est que lorsque je crée une nouvelle implémentation, j'écris à nouveau les tests:
- La sous-classe appelle-t-elle une méthode requise donnée?
- Une méthode donnée a-t-elle une annotation donnée?
- Dois-je obtenir les résultats attendus de la méthode A?
- Dois-je obtenir les résultats attendus de la méthode B?
Bien voir les avantages de cette approche:
- Il documente les exigences de la sous-classe grâce à des tests
- Il peut échouer rapidement en cas de refactoring problématique
- Testez la sous-classe dans son ensemble et via leur API publique («est-ce que methodA () fonctionne?» Et non «cette méthode protégée fonctionne-t-elle?»)
Le problème que j'ai est que les tests pour une nouvelle sous-classe sont fondamentalement une évidence: - Les tests sont tous les mêmes dans toutes les sous-classes, ils changent juste le type de retour des méthodes (l'implémentation du squelette est générique) et les propriétés I vérifier la partie affirmative du test. - Habituellement, les sous-classes n'ont pas de tests qui leur sont spécifiques
J'aime la façon dont les tests se concentrent sur le résultat de la sous-classe elle-même et le protègent contre la refactorisation, mais le fait que la mise en œuvre du test soit devenu un "travail manuel" me fait penser que je fais quelque chose de mal.
Ce problème est-il courant lors du test de la hiérarchie des classes? Comment puis-je éviter cela?
ps: J'ai pensé à tester la classe squelette, mais il semble également étrange de créer une maquette d'une classe abstraite pour pouvoir la tester. Et je pense que tout refactoring sur la classe abstraite qui change un comportement qui n'est pas attendu par la sous-classe ne serait pas remarqué aussi rapidement. Mes tripes me disent que tester la sous-classe "dans son ensemble" est l'approche préférée ici, mais n'hésitez pas à me dire que je me trompe :)
ps2: J'ai googlé et trouvé de nombreuses questions sur le sujet. L'un d'eux est celui qui a une excellente réponse de Nigel Thorne, mon cas serait son "numéro 1". Ce serait formidable, mais je ne peux pas refactoriser à ce stade, donc je devrais vivre avec ce problème. Si je pouvais refactoriser, j'aurais chaque sous-classe comme stratégie. Ce serait OK, mais je testerais toujours la "classe principale" et testerais les stratégies, mais je ne remarquerais aucune refactorisation qui rompt l'intégration entre la classe principale et les stratégies.
ps3: J'ai trouvé des réponses disant "c'est acceptable" pour tester la classe abstraite. Je suis d'accord que c'est acceptable, mais je voudrais savoir quelle est l'approche préférée dans ce cas (je commence toujours par des tests unitaires)