Bureau 223 - extension M3 mirabelle.nebut at univ-lille.fr 2016-2017
2 questions récurrentes et duales pour le testeur Quand s arrête-t-on de tester? on ne peut pas tester tous les comportements ; tester ne fait qu augmenter la confiance qu on a dans le code. Comment sélectionner les bons tests? un test qui décèle un bug est bon ; et un test qui ne décèle rien?
Quand s arrête-t-on de tester? La meilleure réponse selon moi : vient avec l expérience. Autre réponse : calculer une mesure, une métrique, un taux ; se baser pour ce faire sur la forme du code ou de la spécification ; s arrêter quand la mesure a atteint un niveau satisfaisant (ce qui déporte le problème!). Approche théorique du test, historiquement plus ancienne, très différente de l approche TDD.
Comment sélectionner les bons tests? On utilise implicitement ou explicitement un critère de sélection de test. Exemples : sélection de tests pour tester une fonctionnalité (SVL jusqu à présent) ; s assurer que toutes les instructions du programme ont été exécutées. Ce sont deux critères très différents : l un est purement sémantique ; l autre est purement syntaxique.
Critères de sélection de test purement sémantique Par exemple test d une fonctionnalité (SVL jusqu à présent) : basé sur les comportements que décrit la spécification. souvent appelé critère de test fonctionnel ; ne s intéresse pas du tout à la forme de la spécification ; ne s intéresse pas du tout à la forme du code. ne permet pas de définir une mesure autre que j ai testé 5 fonctionnalités sur 12.
Critères de sélection de test syntaxiques Par exemple : exécution de toutes les instructions d un programme ; pour une condition a and b : les conditions a et b et a and b sont au moins une fois à vrai, au moins une fois à faux dans la suite de test. Critères basés sur la forme du code ou de la spécification. possible de compter tous les objets à couvrir (exécuter, valuer, etc) ; taux de couverture du genre x objets couverts sur y possibles. On parle de critères de test structurels.
Dans ce cours Critères de sélection de test structurels basés sur le graphe de contrôle : tous les nœuds (toutes les lignes) ; toutes les branches = critères disponibles via l outillage. Évocation d autres critères (expressions booléennes, domaines infinis). : génération de DT et exécution symbolique.
Introduction
Principes et buts test en boîte de verre basé sur l examen du code source ; basé sur un modèle du code : graphe de flot de contrôle ; graphe de flot de données ; permet de mesurer l adéquation d une suite de test en terme du pourcentage d objets sensibilisés dans ce graphe ; permet de sélectionner des données de test (DT) pour augmenter cette adéquation. N a pas pour but de trouver des oracles, absents de la théorie.
Graphe de flot de contrôle : noeuds Les noeuds représentent soit : un bloc d instructions séquentielles sans aucun transfert de contrôle (pas d instuctions à saut) - graphiquement un rectangle ; un prédicat (noeud de décision) qui permet le transfert du contrôle - graphiquement un losange. On peut utiliser un seul type de noeud. Deux noeuds particuliers : un unique noeud d entrée (sans prédécesseur, permet d accéder transitivement à tous les noeuds du graphe) ; un unique noeud de sortie (sans successeur, accessible transitivement à partir de tous les noeuds du graphe) ;
Graphe de flot de contrôle : arcs Un arc entre deux noeuds n1 et n2 représente le transfert du contrôle de n1 à n2 : avec étiquetage par une condition booléenne c : transfert si c est vraie ; sans étiquetage : transfert inconditionnel. Les structures de contrôle produisent différents graphes : conditionnelle simple ou double ; boucles while, for et do ; exceptions ; break, return, continue. Modèle peu adapté à l objet (lui est antérieur) : penser à un appel de méthodes sur un objet.
Exercice Construire le graphe de contrôle du calcul du triangle de Pascal : 1 int ordre = 4; 2 int [][] tp; 3 tp = new int[ordre+1][]; for (int n = 0; n <= ordre; n++) { 4 tp[n] = new int[n+1]; for (int p=0; p<=n; p++) 5 boolean caspart = (p==0) (p==n) if (caspart) 6 tp[n][p] = 1; else 7 tp[n][p] = tp[n-1][p-1] + tp[n-1][p]; }
Chemin de contrôle dans un graphe Suite d arcs adjacents reliant l entrée à la sortie. Il représente une exécution possible du code. Exemple pour une boucle : --- / \ (a)-->(b)-->(c) (d) L ensemble des chemins est : abd + abcbd + abcbcbd +... ; \ / a(bc + bcbc)bd +... ; --------/ a(bc)*bd. Une DT sensibilise un chemin de contrôle si pour cette DT l exécution du contrôle suit ce chemin.
Critères de couverture : principes Un critère C est une méthode de sélection qui fournit un ensemble de chemins de contrôle à couvrir (ou plus généralement un ensemble d objets à couvrir, quand on travaille sur un autre modèle que le graphe de contrôle). À tout critère C est associé un taux de couverture : nb objets dénotés par C nb objets effectivements couverts Quantité de critères plus ou moins exotiques.
Critère tous les chemins Critère le plus fort. Impossible à obtenir dès la présence d une boucle. NB : différent du test exhaustif qui correspondrait à tous les chemins avec toutes les valeurs possibles (encore moins faisable).
Critère tous les noeuds Aussi appelé Statement Coverage ou TER1 (Test effectiveness ratio). Critère le plus faible. Principes : dénote l ens des chemins qui couvrent l ensemble des noeuds du graphe. taux de couverture = nb noeuds couverts nb noeuds total couverture 100% = toutes les instructions ont été exécutées au moins une fois. S implante facilement avec un compteur d instructions.
Critère tous les arcs : exemple... (a) if (x!=0) (a) x!=0 / \ x=0 x = 1; (b) (b) /... \/ y = 1/x; (c) (c) la DT {x=2} satisfait le critère tous les noeuds : elle sensibilise le chemin abc ; mais ne permet pas de détecter l erreur en (c) ; car le chemin révélateur d erreur est ac ; il aurait fallu couvrir les deux branches du if : critère tous les arcs.
Critère tous les arcs Appelé aussi Decision Coverage ou toutes les branches ou TER2. dénote l ens des chemins qui couvrent tout(e)s les arcs/branches ; chaque prédicat a pris au moins une fois la valeur vrai et la valeur faux ; taux de couverture : nb arcs couverts nb arcs total Souvent implanté dans les outils. tous les arcs tous les noeuds, mais pas l inverse.
Relation d ordre entre critères On dit que le critère C1 est plus fort que le critère C2 si : l ens d objets dénotés par C2 est inclus dans celui dénoté par C1 ; toute faute détectée par C2 l est par C1 ; toute suite de test qui passe pour C1 passe pour C2 ; un taux de couverture de X% pour C1 implique un taux au moins égal à X pour C2 ; On note C2 C1, ou C1 C2. Tous les arcs tous les noeuds, tous les noeuds tous les arcs. Il existe des critères incomparables.
À quoi sert le calcul de la couverture? Si on développe en TDD : par principe couverture avoisinant les 100%. peut indiquer qu on a oublié son test first Si on n est pas en test first : le test structurel s applique au niveau unitaire au niveau intégration Permet de vérifier qu une suite de tests donnée couvre l ensemble du code (en pratique, une suite de tests basée sur des critères sémantiques couvre entre 40 et 60% du code)
Complémentarité structurel / fonctionnel Les critères fonctionnels détectent + facilement les omissions ds la code. Les critères structurels détectent + facilement les choses exotiques ou superflues (sans rapport avec les spécifications). Toujours appliquer d abord les critères sémantiques.
Attention danger! Ne surtout pas faire : coder puis écrire des tests le nez sur le code, qui couvriront 100% des branches et 0% des bugs! Code couvert à 100% ne veut pas dire correct à 100%! Si test d un code étranger : pas d excès de zèle. 80% iront très bien.
Outillage Le plus souvent : couverture tous les noeuds et toutes les branches. Le graphe de contrôle n est pas construit, le code est instrumenté : soit au niveau du code source ; soit au niveau du byte-code. Production d un rapport de couverture. Clover : outil commercial, très bonne intégration dans les environnements de développement, très cher ; jcoverage (commercial, GPL) ou Covertura (open-source) ; emma (open-source), EclEmma (pluggin Eclipse).
Démo coverage
Remarque : prise en compte des conditions Dans le cas de prédicats composés, la décision est composée de plusieurs conditions. Ex x and y : le critère tous les arcs est satisfait : avec deux DT telles que x and y vaudra vrai, et x and y vaudra faux ; par ex {x=t,y=t}, {x=f,y=t}
Remarque : prise en compte des conditions Mais si on considère les conditions dans le graphe (ici avec un et paresseux Java) : (a)!x / \ x (c)!y/ \y / (d) (b) La DT {x=t,y=t}, {x=f,y=t} ne sensibilise pas tous les arcs. Vu comme ça, le critère tous les arcs dépend de la manière dont le programme est compilé. Dépend des outils.
Problème plus large : faire face à la combinatoire Étant donnée une décision composée de plusieurs conditions......quelles valeurs donner aux conditions? si approche fonctionnelle : quelles valeurs choisir parmi les possibles pour tester au mieux un comportement donné? si approche structurelle : en considérant syntaxiquement la décision, quelles DT choisir pour la couvrir. On parle ici de couverture (de code, de spécification) basée sur les données. Beaucoup de travaux théoriques.
Exemple aéronautique WOW = (RG and RD) or (V < 40 and AV) WOW = weight on wheel ; RG / RD : roue gauche / droite ; V : vitesse ; AV : Airspeed valid Comment choisir des valeurs pour tester la valeur de WOW? 2 types de domaines, techniques différentes : booléen (fini) : RG, RD, AV numérique infini : V On peut abstraire le V < 40 en un atome booléen Vb.
Critères combinatoires booléens Différents critères permettant d attribuer rigoureusement des valeurs aux conditions booléennes : tous les variants toutes les conditions MC/DC (Modified Condition / Decision Coverage) toutes les paires... Savoir que ça existe et se référer à la littérature si besoin.
Critère tous les variants Si n conditions alors 2 n variants : explosion combinatoire ; Dans l exemple : 16 variants (2 4 ) ; impraticable.
Critère toutes les conditions/décisions Critère toutes les conditions : Chaque condition doit valoir une fois V et une fois F dans la suite de test ; Deux DT suffisent (n fois V, n fois F) ; Limité. Critère toutes les décisions : idem mais impose en plus que la décision soit au moins une fois à vrai et au moins une fois à faux.
critère MC/DC (Modified Condition / Decision Coverage) Examine la manière dont chaque condition seule influence la décision. Modèle de faute : on vérifie que chaque variable isolément influence bien le résultat. On cherche des DT tq : chaque condition est une fois V et une fois F dans l ensemble des DT ; idem pour la décision ; pour chaque condition il existe 2 DT tq seules la valeur de la décision et celle de cette condition changent. n+1 DT suffisent.
Exemple : a or b table de vérité : a b a or b V V V 1 V F V 2 F V V 3 F F F 4 on garde le 4, et un variant pour a, un variant pour b : 2 et 3 On peut réorganiser le tableau pour qu entre 2 lignes consécutives une seule valeur varie côté entrées, en faisant varier le résultat : a b a or b V F V 2 F F F 4 F V V 3 WOW = (RG and RD) or (Vb and AV)? En 5 DT.
Critère toutes les paires Modèle de faute : erreur dans l interaction entre 2 variables. La plupart des fautes sont détectées par une combinaison de 2 valeurs de variables. Exemple typique : valeurs des options d une commande shell, domaines finis mais non booléens. Si 3 options possibles a b c, et chaque option peut prendre les valeurs 1 2 3 : Tous les variants = 27 variants ; 9 paires (a,b), 9 paires (a,c), 9 paires (b,c) = 27 paires. Autre exemple typique : un système avec 3 paramètres importants : l OS (XP, Vista, Linux), le type de browser (Firefox, IE, Opera), et le type de réseau (IP, Wifi, VPN).
Critère toutes les paires But du jeu : rassembler le test des paires en le moins possible de DT. Dans l ex : on peut combiner les 27 paires en 9 tuples (a,b,c) (= 9 DT), mais ils ne sont pas facile à trouver, ça relève du sudoku. À la main, on peut faire un carré latin (= pas 2 valeurs différentes par ligne et colonne), intuitif a1 a2 a3 b1 c1 c2 c3 b2 c2 c3 c1 b3 c3 c1 c2 Si plus de 3 valeurs, ou plus de variables : plus un carré, et très difficile. Outils : tableaux orthogonaux.
Domaines infinis Approche catégorie / partition basée sur les limites des domaines. Savoir que ça existe et se référer à la littérature si besoin. Ex typiques : calcul de feuille d impôt, d assurance.
Introduction
Choix d une DT pour sensibiliser un chemin Le faire à la main est très difficile. Il arrive qu un chemin soit non-exécutable : aucune DT ne peut le sensibiliser. Chemins non-exécutables = casse-tête du testeur. Peuvent signaler : du code mort ; ou une erreur de codage. Seule solution : adopter des outils automatiques de sensibilisation capables de fournir les DT qui sensibilisent un chemin donné.
Exemple if (x <= 0) (a) (a) x = -x; (b) x<=0 / \ x > 0 else (b) (c) x = 1 - x; (c) \ / if (x == -1) (d) (d) y = 0; (e) x = -1 / \ x!= -1 else (e) (f) y = x - 1; (f) \ / S.O.P(1/y); (g) (g) // erreur en (g) si (S) // y vaut 0
Exemple - quelle valeur pour x? if (x <= 0) x = -x; else x = 1 - x; if (x == -1) y = 0; else y = x - 1; S.O.P(1/y); (a) (b) (c) (d) (e) (f) (g) 4 chemins possibles : ch1 = abdeg, ch2 = acdeg ch3 = abdfg ch4 = acdfg Existe-t-il une valeur de x tq en (g) on a y = 0? // erreur en (g) si // y vaut 0
Problème général Un outil peut-il répondre de manière systématique, quel que soit le programme et un chemin de ce programme, à la question : existe-t-il des valeurs pour les entrées du programme tq ce chemin est exécuté? Et si la réponse est oui, fournir les valeurs, tant qu à faire...
Réponse pas marrante Problème indécidable! NON
Réponse de normand Selon la forme du programme : parfois OUI. Outils basés sur l exécution symbolique du programme : représentation des chemins par une formule logique ; utilisation de solveurs SAT / SMT ; si la formule est satisfaisable alors le chemin est exécutable l outil sait produire des valeurs qui satisfont la formules = les DT Solveurs SMT de + en + puissants.
Démo avec pyexz3 Outil de proof of concept, python sans objets seulement. Se décharge sur le solveur SMT z3. Arrêt si levée d exception ou erreur.
Démo avec Pex
Conclusion Spectre très vaste pour les travaux autour du test. Approches pragmatiques, génie logiciel, TDD, mocks, etc. Approches théoriques, métriques, méthodes issues du monde de la vérification/preuve pour calculer des DT, etc. Génération automatique de cas de test à partir de spec.