Automatisation de la création de tests unitaires

11

Quelles stratégies pourraient être utilisées pour automatiser la création de cas de tests unitaires? Quels aspects devez-vous examiner dans chaque classe pour pouvoir générer au moins un squelette décent?

Je me rends compte qu'une solution automatique complète n'est pas pratique, mais j'aimerais accélérer un peu la création du test en créant au moins un squelette. Je ne cherche pas d'exemples de code, juste peut-être quelques suggestions par où commencer ou des exemples où quelque chose comme ça a été fait pour que je puisse voir comment ils l'ont abordé et ce qui pourrait être possible.

Je suis particulièrement intéressé par les méthodes de création de squelettes de tests unitaires en PHP, qui ne fournissent pas tous les outils que les autres langages offrent, comme l' indication de type complète , par exemple.

VirtuosiMedia
la source
Le dernier Visual Studio est tout ce dont vous avez besoin ...
Job

Réponses:

5

Votre stratégie et votre squelette dépendent, de manière non triviale, des types de tests que vous cherchez à générer, du type de couverture que vous recherchez et de la langue / de l'environnement dans lequel vous travaillez.

Il est assez simple d'écrire un générateur de test qui, pour des langages comme C ou Java, lit les signatures de classe et génère automatiquement des tests pour les cas d'angle standard (passage de 0, 2 valeurs aléatoires, MAX_INT, MIN_INT, à un argument entier, null pour nullables , etc...). Vous pouvez ensuite exécuter les tests générés, enregistrer les résultats de chaque test et les filtrer manuellement pour supprimer ceux qui ne sont pas pertinents, approuver les résultats acceptables pour les tests qui réussissent (afin qu'ils puissent passer automatiquement à partir de là) et les marquer comme invalides qui échouent .

Vous pouvez augmenter cela avec le balisage / commentaire / refactorisation des classes pour aider votre générateur avec des conseils supplémentaires. Vous pouvez avoir une balise qui répertorie toutes les exceptions possibles qu'un appel de méthode est autorisé à lever, ou qui donne une plage réduite d'entiers valides pour un argument entier. Considérez-les comme un raccourci pour avoir à passer les tests vous-même.

Donc, voici quelques composants que vous voudrez regarder:

  • Un composant pour analyser automatiquement le code source / les signatures de fonction / annotations manuelles, produisant des cas de test standard, ou des contours / signatures pour les cas de test qui attendent la fin de votre entrée.
  • Un langage de balises / annotations / commentaires perpétuellement croissant / changeant qui peut aller à n'importe quel niveau de granularité (méthode / classe / signature / boucles while / etc ...) représentant des conseils pour le générateur de tests automatisé. Idéalement, vous devriez pouvoir jouer avec ce langage sans avoir à recoder votre framework ou ses morceaux
  • Runner de test automatisé, avec la capacité d'identifier les nouveaux / anciens tests et d'enregistrer / tester les réponses "acceptables" pour chaque test. Idéalement, ce coureur construira une base de données des essais, des résultats acceptés / refusés et des résultats acceptables actuels pour chaque essai.
  • "Objet faker" automatisé qui, étant donné un nom de classe et une carte de noms-> valeurs, peut générer un objet imitant la classe, renvoyant des données personnalisables pour les appels de fonction, les accesseurs, les emplacements de données publics, etc.

Il existe de nombreux frameworks de test qui incluent déjà des morceaux de cette fonctionnalité pour différents langages et plates-formes. Bien qu'il soit assez facile de commencer à faire ce travail vous-même et de développer ce type de cadre de manière organique en interne, il s'agit également d'un projet à long terme sans fin qui reproduira probablement le travail existant. Je recommanderais de prendre beaucoup de temps pour regarder ce qui est disponible en premier, puis décider si cela vaut la peine de plonger.

blueberryfields
la source
5

Je n'ai pas encore eu l'occasion de l'utiliser sur une application d'une taille ou d'une complexité significative, mais il existe des outils, dont CodePro AnalytiX de Google , qui automatisent la génération de tests unitaires pour les applications Java . J'ai également trouvé un produit commercial, le test C ++ de Parasoft , qui semble permettre la génération de tests unitaires C ++

Ces applications ont utilisé l'heuristique pour générer des cas de test. Je ne suis pas sûr qu'il existe un cadre unique que vous pouvez utiliser pour produire un squelette, mais il existe des constructions que vous pouvez rechercher. J'ai tendance à me concentrer sur les boucles, les instructions conditionnelles ( ifblocs, switch/ caseinstructions) et les exceptions, et à créer des cas de test qui forcent l'exécution de différents chemins d'exécution.

Je ne me concentrerais pas sur l'accélération de l'écriture des tests en essayant de créer un squelette ou un modèle, mais plutôt en améliorant l'analyse de la spécification et / ou de l'implémentation et en écrivant des tests de haute qualité. Être en mesure d'identifier rapidement les tests qui ajoutent le plus de valeur, de les écrire, puis de combler les trous plus tard aurait un impact plus important sur la productivité et la qualité.


Juste pour fournir plus de publicité, Falcon a essayé CodePro sur un projet et a écrit un petit texte sur ses expériences .

Thomas Owens
la source
CodePro Analytix de Google semble intéressant. Mais "Quis custodiet ipsos custodes?" Qui teste les tests? Cela ne peut être utilisé que pour sauvegarder un projet existant par des tests unitaires et ne détectera probablement pas les échecs, il supposera plutôt que les défauts sont corrects.
Falcon
@Falcon Vous ne pouvez faire confiance aveuglément à aucun outil - cela ne fera que causer plus de maux de tête. Je pense que le conseil du programmeur pragmatique "se soucier de votre métier" s'applique ici. CodePro contient un éditeur de test pour le rendre trivial pour voir quelles valeurs sont transmises et quel est le résultat attendu, puis pour y apporter des modifications (puis mettre à jour le code de test généré pour refléter ces modifications).
Thomas Owens
Je me demande simplement ce qui est plus fiable dans ce cas, humain ou machine. Je pense que ces tests générés causeront plus de maux de tête que les tests écrits manuellement. Idéalement, le test devrait être écrit en premier de toute façon. Mais je vais certainement essayer. J'aimerais voir un outil qui peut générer des tests basés sur des exigences formelles et de la colle de métadonnées pour interfacer un jour le système.
Falcon
@Falcon Oui, idéalement, certains tests devraient être écrits en premier, mais jusqu'à ce que vous ayez une implémentation et que vous puissiez faire des tests en boîte blanche, vous ne voyez pas nécessairement tous les différents cas marginaux que vous pouvez voir une fois que vous avez une implémentation. Si vous avez la possibilité de jouer avec les fonctionnalités de génération de test de CodePro, pourriez-vous poster vos réflexions quelque part et obtenir en quelque sorte un lien? Je suis intéressé de voir à quel point cela fonctionne et l'expérience des autres avec.
Thomas Owens
Je vais le tester la semaine prochaine avec une application J2EE de taille moyenne (120 klocs) qui incorpore des règles commerciales vraiment dures et vous parler de mes expériences ici.
Falcon
1

J'ai écrit un générateur pour accélérer les tests unitaires d'un projet .NET il y a quelques années. Il y avait une grande base de code sans tests unitaires et elle visait à augmenter rapidement la couverture de base. Voici quelques notes qui pourraient vous être utiles:

  • Ma chance était que le cadre principal sur lequel le projet a été développé fournissait des opérations standard et un nom de classe. Si vous envisagez d'écrire la vôtre, une structure standard comme celle-ci vous aidera grandement.
  • L'utilisation data-driven testingaide beaucoup, si votre base de code le permet. Le cadre de test a créé une table de base de données pour chaque test unitaire afin de stocker les données de test, de sorte que chaque ligne de cette table était un test distinct et qu'aucun code supplémentaire n'était requis ( règle de représentation ). À partir de ce moment, les tests réels peuvent être facilement créés automatiquement ou saisis manuellement.
  • Les tests unitaires résultants étaient simples mais ils ont servi d' smoke testau moins de s. Pour les zones à haut risque, des tests manuels supplémentaires ont été rédigés.

Pour résumer, je conviens qu'une solution générique serait peu pratique (si c'est possible). Je pense que les chances sont meilleures si la base de code est adaptée à la génération de tests et que le framework de test peut tirer parti de sa structure.

(En note, il y a Pex , mais c'est pour .NET)

henginy
la source