44 votes

Doit-on tester la mise en œuvre interne, ou seulement le comportement du public?

Logiciel donné où ...

  • Le système se compose de quelques sous-systèmes
  • Chaque sous-système se compose de quelques composants
  • Chaque volet est mis en œuvre à l'aide de nombreuses classes

... J'aime écrire des tests automatisés de chaque sous-système ou d'un composant.

Je ne suis pas d'écrire un test pour chaque classe interne d'un composant (sauf dans la mesure où chaque classe contribue à la composante publique de fonctionnalités et qui est donc vérifiable/testé à partir de l'extérieur via le composant de l'API publique).

Quand je refactoriser la mise en œuvre d'un composant (qui je le fais souvent, dans le cadre de l'ajout de nouvelles fonctionnalités), donc je ne pas besoin de modifier un existant tests automatisés: parce que les tests dépendent uniquement de la composante publique de l'API, et les Api publiques sont généralement en cours d'expansion plutôt que modifié.

Je pense que cette politique contraste avec un document comme le Refactoring de Code de Test, qui dit des choses comme ...

  • "... les tests unitaires ..."
  • "... une classe de test pour chaque classe dans le système ..."
  • "... test de code / code de production de rapport ... est idéalement considéré comme à l'approche d'un ratio de 1:1 ..."

... je suppose que je suis en désaccord avec (ou au moins ne pratique pas).

Ma question est, si vous êtes en désaccord avec ma politique, voulez-vous expliquer pourquoi? Dans quels cas est ce degré de tests insuffisants?

En résumé:

  • Les interfaces publiques sont testés (et testés), et changent rarement (ils sont ajoutés à mais rarement modifié)
  • Interne de l'Api sont cachés derrière les Api publiques, et peut être modifié sans avoir à réécrire les cas de test qui test les Api publiques


Note: certains de mes "cas de test" sont en fait mis en œuvre en tant que données. Par exemple, les cas de test de l'INTERFACE utilisateur sont constitués de fichiers de données qui contiennent des différentes entrées de l'utilisateur et le système des sorties. Les tests du système ayant des moyens de code de test qui lit chaque fichier de données, les replays l'entrée dans le système, et affirme qu'il devient le correspondant prévu de sortie.

Bien que j'ai rarement besoin de changer le code de test (parce que les Api sont généralement ajoutés à plutôt que modifié), je trouve que j'ai parfois (par exemple, deux fois par semaine) la nécessité de modifier certains fichiers de données existants. Cela peut se produire lorsque j'ai changer le système de sortie pour le mieux (c'est à dire une nouvelle fonctionnalité améliore l'existant de la sortie), ce qui pourrait causer un test existant pour "échouer" (parce que le code de test essaie seulement d'affirmer que la production n'a pas changé). Pour gérer ces cas je ne les suivants:

  • Réexécutez le test automatisé suite une exécution drapeau, qui lui dit de ne pas faire valoir la sortie, mais au lieu de saisir la nouvelle sortie dans un nouveau répertoire
  • Utiliser un visual diff pour voir l'outil de sortie de fichiers de données (c'est à dire que les cas de test), et de vérifier que ces changements sont bons et comme prévu, compte tenu de la nouvelle fonctionnalité
  • Mettre à jour les tests existants par la copie des nouveaux fichiers de sortie de ce nouveau répertoire dans le répertoire à partir de laquelle les cas de tests sont exécutés sur l'écriture de la vieille tests)


Note: par "composant", je veux dire quelque chose comme "une DLL" ou une "assemblée" ... quelque chose qui est assez grand pour être visible sur une architecture ou d'un diagramme de déploiement du système, souvent mis en œuvre à l'aide de dizaines ou de 100 classes, et avec une API publique qui se compose de seulement 1 ou une poignée d'interfaces ... quelque chose qui peut être attribué à une équipe de développeurs (où un composant différent est attribué à un autre de l'équipe), et qui sera donc en fonction de Conway Droit d'avoir une relative stabilité de l'API publique.


Note de bas de page: L'article Orienté Objet les Tests: le Mythe et la Réalité dit,

Mythe: la boîte Noire est suffisant. Si vous faites attention à l'emploi des cas de test de la conception à l'aide de l'interface de classe ou spécification, vous pouvez être assuré que la classe a été entièrement levées. Blanche-boîte de test (à la recherche à un la méthode mise en œuvre pour la conception les tests) viole le concept même de l'encapsulation.

Réalité: OO structure de la matière, de la partie II. De nombreuses études ont montré que boîte noire des suites de test pensé pour être atrocement approfondie par les développeurs seulement l'exercice d'un tiers à une moitié des déclarations (sans parler de chemins d'accès ou de les états dans la mise en œuvre en vertu de test. Il y a trois raisons pour c'. Tout d'abord, les entrées ou les états sélectionné généralement exercice normal chemins d'accès, mais ne force pas possible des chemins et des etats. Deuxièmement, black-box test seul ne peut pas révéler de belles surprises. Supposons que nous avons testé toutes les spécifié comportements du système en cours de test. Pour être sûr il y a des pas non spécifié comportements que nous avons besoin de savoir si toutes les parties du système ont pas été exercé par la boîte noire suite de test. Le seul moyen d' des renseignements peuvent être obtenus est par code l'instrumentation. Troisièmement, il est souvent difficile l'exercice d'exception et gestion des erreurs sans examen de le code source.

Je dois ajouter que je suis en train de faire de la whitebox test fonctionnel: - je voir le code (dans la mise en œuvre) et j'écris des tests fonctionnels (dont le lecteur de l'API publique) d'exercer les diverses branches de code (les détails de la fonctionnalité de mise en œuvre).

30voto

Bluebird75 Points 4612

La réponse est très simple: vous êtes décrivant les tests fonctionnels, qui est une partie importante de la software assurance de la qualité. Les tests internes de mise en œuvre est l'unité de test, qui est une autre partie de la QA de logiciel avec un objectif différent. C'est pourquoi vous vous sentez que les gens sont en désaccord avec votre approche.

Le test fonctionnel est important de valider que le système ou sous-système fait ce qu'il est censé faire. Tout ce que le client voit doit être testé de cette façon.

Unité de test est ici de vérifier que les 10 lignes de code que vous venez d'écrire est ce qu'il est censé faire. Il vous donne plus de confiance de votre code.

Les deux sont complémentaires. Si vous travaillez sur un système existant, les tests de fonctionnement est la première chose à travailler sur probablement. Mais dès que vous ajoutez un code, tests unitaires, c'est une bonne idée aussi.

18voto

mouviciel Points 36624

Ma pratique est de tester les internes via l'API / UI publique. Si un code interne ne peut pas être atteint de l'extérieur, je le refacture pour le supprimer.

9voto

darch Points 2642

Je n'ai pas mon exemplaire de Lakos en face de moi, donc, plutôt que de citer je me contenterai de souligner qu'il fait un meilleur travail que je vais expliquer pourquoi les tests est importante à tous les niveaux.

Le problème avec le test "le comportement du public" est un test vous donne très peu d'informations. Il va attraper de nombreux bugs (comme le compilateur va attraper de nombreux bugs), mais ne peut pas vous dire où les insectes sont. Il est courant pour un mal mises en œuvre unité de retour de bonnes valeurs pour une longue période et puis cesser de le faire lorsque les conditions changent; si l'unité a été testée directement, le fait qu'il a été mal mis en œuvre aurait été évident tôt.

Le meilleur niveau de test granularité est le niveau de l'unité. Fournir des analyses pour chaque unité par le biais de son interface(s). Cela vous permet de valider et documenter vos croyances sur le fonctionnement de chaque composant se comporte, ce qui vous permet de tester le code dépendant seulement de tester la nouvelle fonctionnalité qu'il présente, qui maintient des tests à court et sur la cible. En prime, il conserve des tests avec le code, ils ont testé.

À l'expression il différemment, il est exact que pour tester le comportement du public, aussi longtemps que vous remarquez que chaque visibles publiquement de la classe a le comportement du public.

8voto

Ed Altorfer Points 3392

Il y a eu beaucoup de réponses à cette question pour le moment, mais je tiens à ajouter quelques notes de mon propre. En préambule: je suis consultant pour une grande entreprise qui fournit des solutions technologiques pour une large gamme de clients. Je dis cela parce que, dans mon expérience, nous sommes tenus de test beaucoup plus en profondeur que la plupart des magasins de logiciel faire (peut-être sauver développeurs d'API). Voici les étapes que nous devons suivre pour s'assurer de la qualité:

  • Interne De L'Unité De Test:
    Les développeurs devraient créer des tests unitaires pour tout le code qu'ils écrivent (lire: chaque méthode). Les tests unitaires doivent couvrir positive des conditions de test (ma méthode de travail?) et négatifs des conditions de test (la méthode de jeter une ArgumentNullException quand un de mes arguments requis est null?). En général, nous pouvons intégrer ces tests dans le processus de construction à l'aide d'un outil comme CruiseControl.net
  • Test Du Système De Montage / Test De:
    Parfois, cette étape est appelée quelque chose de différent, mais c'est lorsque nous avons commencer le test public de la fonctionnalité. Une fois que vous savez toutes les unités de fonctionner comme prévu, vous voulez savoir qui de vos fonctions externes travaillent également à la façon dont vous pensez qu'ils devraient. C'est une forme de la fonctionnelle de la vérification, car le but est de déterminer si le système fonctionne comme il le devrait. Notez que cela n'inclut pas les points d'intégration. Pour le test du système, vous devriez être en utilisant moqué-des interfaces au lieu de le réel, de sorte que vous pouvez contrôler la sortie et de construire des cas de test autour d'elle.
  • L'Intégration Du Système De Test:
    À ce stade du processus, vous voulez vous connecter à vos points d'intégration au système. Par exemple, si vous utilisez une carte de crédit, vous aurez envie d'intégrer le système live, à ce stade, pour vérifier qu'il fonctionne toujours. Vous souhaitez effectuer des tests similaires à système de montage/test.
  • Contrôle Des Fonctions De Test:
    Contrôle des fonctions pour les utilisateurs du système ou à l'aide de l'API pour vérifier qu'il fonctionne comme prévu. Si vous avez construit un système de facturation, c'est l'étape au cours de laquelle vous pourrez exécuter vos scripts de test de bout en bout pour s'assurer que tout fonctionne comme vous l'avez conçu. C'est évidemment une étape critique dans le processus, car il vous indique si vous avez fait votre travail.
  • Test De Certification:
    Ici, vous mettez de vrais utilisateurs à l'avant du système et let 'em avoir un aller à elle. Idéalement, vous avez déjà testé votre interface utilisateur à un certain point avec vos parties prenantes, mais cette étape va vous dire si votre public cible aime votre produit. Vous avez peut-être entendu parler de ce qu'on appelle quelque chose comme une "release candidate", par d'autres vendeurs. Si tout va bien, à ce stade, vous savez que vous êtes bon pour passer à la production. Les tests de Certification doit toujours être effectuée dans le même environnement que vous allez utiliser pour la production (ou à l'identique de l'environnement au moins).

Bien sûr, je sais que tout le monde suit ce processus, mais si vous regardez à partir de la fin à la fin, vous pouvez commencer à voir les avantages de chacun de ses composants. Je n'ai pas compris des choses comme la vérification de la génération des tests car ils se trouvent sur un autre scénario (par exemple, tous les jours). Personnellement, je crois que les tests unitaires sont cruciaux, car ils vous donnent un aperçu en profondeur dans laquelle les composants spécifiques de votre application est en échec, auquel cas d'utilisation spécifiques. Les tests unitaires seront également vous aider à identifier les méthodes qui fonctionnent correctement de sorte que vous ne perdez pas de temps à les regarder pour plus d'informations sur un échec quand il n'y a rien de mal avec eux.

Bien sûr, les tests unitaires pourraient également être tort, mais si vous développez vos cas de test à partir de votre fonctionnelles/techniques de spécification (vous en avez un, droit? ;)), vous ne devriez pas avoir trop de mal.

2voto

Karl the Pagan Points 598

Si vous êtes à la pratique pure développement piloté par les tests, vous n'en œuvre de tout code une fois que vous avez des test en échec, et seulement de mettre en œuvre le code de test lorsque vous n'avez pas de faute de tests. En outre, de mettre en œuvre la chose la plus simple à faire de l'échec ou de test de passage.

Dans le peu de TDD pratique que j'ai eu j'ai vu comment cela m'aide à débusquer les tests unitaires pour chaque condition logique produite par le code. Je ne suis pas entièrement convaincu que 100% de la logique sont les caractéristiques de mon code confidentiel, est exposée par mes interfaces publiques. Pratiquer le TDD semble gratuit pour que le système métrique, mais il y a encore des fonctionnalités cachées non autorisé par les Api publiques.

Je suppose que vous pourriez dire que cette pratique me protège contre d'éventuels défauts dans mes interfaces publiques. Soit vous trouvez que utile (et vous permet d'ajouter de nouvelles fonctionnalités plus rapidement) ou vous trouvez que c'est une perte de temps.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X