Styles

mardi 24 juin 2008

Génération automatique de tests unitaires par héritage d'assertions

Toujours à propos des assertions, je me demande s'il ne serait pas possible de générer des tests unitaires automatiquement, mais uniquement ceux qui vont faire tomber à FALSE une assertion quelconque de la routine (et à n'importe quelle profondeur). En effet, d'après le livre du magicien, au chapitre 1-1 on peut lire :

Chaque langage puissant a trois mécanismes pour combiner des idées simples pour former des idées plus complexes[1] :

- des "expressions primitives" qui représentent les entités les plus simples dont le langage se préoccupe,

- des "moyens de combinaison" par lesquels des éléments composés sont construit à partir d'éléments plus simples,

- des "moyens d'abstraction" par lesquels les éléments composés peuvent être nommés et manipulés comme des unités.
Si on s'en tient à cette définition, on pourrait imaginer qu'un langage définisse toutes les pré-conditions à respecter pour chaque "expression primitive", les assertions implicites comme par exemple pour la fonction / qui ne peut accepter un dénominateur égal à 0.
Ainsi, si vous programmez du code comme cela (en Scheme par exemple) :
(define (myfunc myval) (/ 10 myval))
Un outil pourrait construire, en analysant les combinaisons et les abstractions, un cas de test unitaire automatiquement pour faire planter cette myfunc() :
(define (myfuncTest) (myfunc 0))
; Le test unitaire généré automatiquement
; d'après l'analyse de myfunc()
On peut dire que myfunc() hérite des préconditions de toutes les fonctions auxquelles la routine fait appel. A noter qu'il n'y a aucune assertion, préconditions, invariants spécifiés au niveau de la routine myfunc(), l'outil doit être capable de les déduire de l'implémentation de la routine (comme c'est ici le cas dans la remontée de la précondition de la routine / )

Reste à définir correctement comment fonctionne l'héritage de préconditions, postconditions et d'invariants. J'ai trouvé un rapport d'étude intéressant visant à produire automatiquement les tests unitaires à partir de conditions (exprimées en JML), mais je n'ai pas trouvé ce mécanisme d'héritage de conditions.

Une solution à base de détection automatique d'invariant par un outil comme Daikon pourrait peut-être faire l'affaire... à creuser.

On peut même rapprocher ce problème à un problème de satisfaction de contraintes. Les paramètres de la routine sont les variables, leur domaine est restreint par leur type, et les pré-conditions, post-conditions, invariants sont les contraintes.

Via les mécanismes d'inférence de contraintes bien connus dans le domaine du traitement des contraintes, on pourrait imaginer calculer quelles sont les solutions (les domaines possibles) des variables de la routine en fonction de tous les appels d'autres fonctions qu'elle réalise. Ces solutions sont les pré-conditions d'appel de la routine.

Tout cela reste à explorer, si une bonne âme souhaite se dévouer à cette tâche...

[1] C'était déjà ce qu'avait noté John Locke dans An Essay Concerning Human Understanding (1690) : "The acts of the mind, wherein it exerts its power over simple ideas, are chiefly these three: 1. Combining several simple ideas into one compound one, and thus all complex ideas are made. 2. The second is bringing two ideas, whether simple or complex, together, and setting them by one another so as to take a view of them at once, without uniting them into one, by which it gets all its ideas of relations. 3. The third is separating them from all other ideas that accompany them in their real existence: this is called abstraction, and thus all its general ideas are made"

Aucun commentaire: