J'ai récemment lu quelques mots sur Literate Programming , et cela m'a fait réfléchir ... Des tests bien écrits, notamment les spécifications de style BDD, permettent de mieux expliquer ce que le code fait que la prose et a le gros avantage de vérifier leur propre précision.
Je n'ai jamais vu de tests écrits en ligne avec le code qu'ils testent. Est-ce simplement parce que les langues ne permettent pas facilement de séparer le code d'application et le code de test lorsqu'ils sont écrits dans le même fichier source (personne ne l'a simplifié), ou y a-t-il une raison plus logique qui sépare le code de test du code d'application?
testing
unit-testing
bdd
literate-programming
Chris Devereux
la source
la source
Réponses:
Le seul avantage auquel je puisse penser pour les tests en ligne serait de réduire le nombre de fichiers à écrire. Avec les IDE modernes, ce n'est pas vraiment un gros problème.
Les tests en ligne présentent toutefois un certain nombre d'inconvénients évidents:
la source
Je peux penser à certains:
Lisibilité. Le fait d'interpréter du code "réel" et des tests rendra plus difficile la lecture du code réel.
Code ballonnement. Mélanger du code "réel" et du code de test dans les mêmes fichiers / classes / tout ce qui est susceptible de donner lieu à des fichiers compilés plus volumineux, etc. Ceci est particulièrement important pour les langues avec liaison tardive.
Vous ne voulez peut-être pas que vos clients / clients voient votre code de test. (Je n'aime cette raison ... mais si vous travaillez sur un projet source fermé, le code de test est peu susceptible d'aider le client de toute façon.)
Il existe maintenant des solutions de contournement possibles pour chacun de ces problèmes. Mais IMO, il est plus simple de ne pas y aller en premier lieu.
Il est intéressant de noter qu'au début, les programmeurs Java faisaient ce genre de chose; Par exemple, inclure une
main(...)
méthode dans une classe pour faciliter les tests. Cette idée a presque complètement disparu. Il est de pratique courante dans l’industrie de mettre en œuvre des tests séparément en utilisant un cadre de test quelconque.Il convient également de noter que la programmation littéraire (telle que conçue par Knuth) n’a jamais fait son chemin dans l’industrie du génie logiciel.
la source
En fait, vous pouvez penser à Design By Contract comme ceci. Le problème est que la plupart des langages de programmation ne vous permettent pas d'écrire du code comme celui-ci :( Il est très facile de tester manuellement les conditions préalables, mais les conditions de publication constituent un véritable défi sans changer la façon dont vous écrivez le code (une OMI extrêmement négative).
Michael Feathers a fait une présentation à ce sujet et c’est l’une des nombreuses façons dont il dit que l’on peut améliorer la qualité du code.
la source
Pour bon nombre des raisons pour lesquelles vous essayez d’éviter un couplage étroit entre les classes de votre code, il est également judicieux d’éviter tout couplage inutile entre les tests et le code.
Création: Les tests et le code peuvent être écrits à des moments différents, par différentes personnes.
Contrôle: si les tests sont utilisés pour spécifier des exigences, vous voudriez certainement qu’ils soient soumis à des règles différentes sur qui peut les changer et quand le code lui-même.
Réutilisation: si vous mettez les tests en ligne, vous ne pouvez pas les utiliser avec un autre morceau de code.
Imaginez que vous ayez un morceau de code qui fasse le travail correctement, mais laisse beaucoup à désirer en termes de performances, de maintenabilité, etc. Vous décidez de remplacer ce code par du code nouveau et amélioré. L'utilisation du même ensemble de tests peut vous aider à vérifier que le nouveau code produit les mêmes résultats que l'ancien code.
Possibilité de sélection: le fait de séparer les tests du code facilite le choix des tests que vous souhaitez exécuter.
Par exemple, vous pouvez avoir une petite suite de tests qui ne concerne que le code sur lequel vous travaillez actuellement, et une suite plus grande qui teste l'ensemble du projet.
la source
Voici quelques raisons supplémentaires auxquelles je peux penser:
avoir des tests dans une bibliothèque séparée facilite la liaison de cette bibliothèque uniquement avec votre framework de test, et non avec votre code de production (cela pourrait être évité par certains pré-processeurs, mais pourquoi le construire de telle sorte que la solution la plus simple est d'écrire les tests en un endroit séparé)
Les tests d'une fonction, d'une classe, d'une bibliothèque sont généralement écrits du point de vue "utilisateurs" (un utilisateur de cette fonction / classe / bibliothèque). Un tel "code d'utilisation" est généralement écrit dans un fichier ou une bibliothèque distinct (e), et un test peut être plus clair ou "plus réaliste" s'il imite cette situation.
la source
Si les tests étaient en ligne, il serait nécessaire de supprimer le code nécessaire au test lorsque vous expédiez le produit à votre client. Ainsi, un emplacement supplémentaire dans lequel vous stockez vos tests sépare simplement le code dont vous avez besoin et le code dont votre client a besoin.
la source
Cette idée revient simplement à une méthode "Self_Test" dans le contexte d'une conception à base d'objet ou orientée objet. Si vous utilisez un langage compilé basé sur des objets comme Ada, tout le code d’autotest sera marqué par le compilateur comme étant inutilisé (jamais appelé) lors de la compilation de la production, et il sera donc optimisé à l’extérieur - aucun d’entre eux n’apparaîtra dans la liste. résultat exécutable.
Utiliser une méthode "Self_Test" est une très bonne idée, et si les programmeurs étaient vraiment soucieux de la qualité, ils le feraient tous. Un problème important, cependant, est que la méthode "Self_Test" doit faire preuve d'une discipline intense, en ce sens qu'elle ne peut accéder à aucun des détails d'implémentation et qu'elle ne doit s'appuyer que sur toutes les autres méthodes publiées dans la spécification de l'objet. Évidemment, si l'autotest échoue, la mise en œuvre devra changer. L'autotest doit être un test rigoureux de toutes les propriétés publiées des méthodes de l'objet, sans jamais s'appuyer de quelque manière que ce soit sur les détails d'une implémentation spécifique.
Les langages basés sur les objets et orientés objet fournissent souvent exactement ce type de discipline en ce qui concerne les méthodes externes à l'objet testé (ils appliquent la spécification de l'objet, empêchant tout accès à ses détails d'implémentation et générant une erreur de compilation si une telle tentative est détectée ). Cependant, les méthodes internes de l'objet disposent d'un accès complet à tous les détails de la mise en œuvre. La méthode d’autotest se trouve donc dans une situation unique: il faut qu’elle soit une méthode interne en raison de sa nature (l’autotest est évidemment une méthode de l’objet testé), mais elle doit recevoir toute la discipline du compilateur d’une méthode externe ( il doit être indépendant des détails d'implémentation de l'objet). Peu ou pas de langages de programmation offrent la possibilité de discipliner un objet ' s méthode interne comme s'il s'agissait d'une méthode externe. Il s’agit donc d’un problème de conception de langage de programmation important.
En l'absence d'un support approprié du langage de programmation, la meilleure façon de le faire est de créer un objet compagnon. En d'autres termes, pour chaque objet que vous codez (appelons-le "Big_Object"), vous créez également un deuxième objet compagnon dont le nom consiste en un suffixe standard concaténé avec le nom de l'objet "réel" (dans ce cas, "Big_Object_Self_Test "), et dont la spécification consiste en une seule méthode (" Big_Object_Self_Test.Self_Test (This_Big_Object: Big_Object) return return Boolean; "). L'objet compagnon dépendra alors de la spécification de l'objet principal et le compilateur appliquera pleinement toute la discipline de cette spécification à l'implémentation de l'objet compagnon.
la source
Cela fait suite à un grand nombre de commentaires suggérant que les tests en ligne ne sont pas effectués car il est difficile, voire impossible, de supprimer le code de test des versions validées. C'est faux. Presque tous les compilateurs et assembleurs le supportent déjà, avec des langages compilés, tels que C, C ++, C #, cela se fait avec ce qu'on appelle des directives de compilateur.
Dans le cas de c # (je crois aussi que c ++, la syntaxe peut être légèrement différente en fonction du compilateur que vous utilisez), voici comment vous pouvez le faire.
Comme il utilise des directives de compilation, le code n'existe pas dans les fichiers exécutables générés si les indicateurs ne sont pas définis. C’est également ainsi que vous créez des programmes "écrire une fois, compiler deux fois" pour plusieurs plates-formes / matériels.
la source
Nous utilisons des tests en ligne avec notre code Perl. Il existe un module, Test :: Inline , qui génère des fichiers de test à partir du code en ligne.
Je ne suis pas particulièrement doué pour organiser mes tests et je les ai trouvés plus faciles et plus susceptibles d'être maintenus en ligne.
Répondant à quelques préoccupations exprimées:
+-- 33 lines: #test----
. Lorsque vous souhaitez travailler avec le test, développez-le.Pour référence:
la source
Erlang 2 prend en charge les tests en ligne. Toute expression booléenne du code qui n’est pas utilisée (par exemple, assignée à une variable ou passée) est automatiquement traitée comme un test et évaluée par le compilateur; si l'expression est fausse, le code ne se compile pas.
la source
Une autre raison de la séparation des tests est que vous utilisez souvent des bibliothèques supplémentaires ou même différentes pour les tests que pour l'implémentation réelle. Si vous combinez des tests et une implémentation, le compilateur ne pourra pas intercepter l’utilisation accidentelle de bibliothèques de tests dans l’implémentation.
En outre, les tests ont généralement beaucoup plus de lignes de code que les composants d'implémentation testés. Vous aurez donc du mal à trouver l'implémentation entre tous les tests. :-)
la source
Ce n'est pas vrai Il est bien préférable de placer vos tests unitaires aux côtés du code de production lorsque ce dernier est utilisé, en particulier lorsque la routine de production est pure.
Si vous développez sous .NET, par exemple, vous pouvez insérer votre code de test dans l'assemblage de production, puis utiliser Scalpel pour le supprimer avant l'expédition.
la source