• Aucun résultat trouvé

Étape 3: Améliorer les contrats

5.3 Expérimentations pour le développement d’un composant de

5.3.4 Étape 3: Améliorer les contrats

Pendant cette troisième étape, nous mettons en œuvre une méthode d’amélioration de la spécification embarquée, sous sa forme de contrats exécutables (figure 5-16). Il s’agit de mettre à l’épreuve ces contrats avec les mutants. Pour cela ils sont utilisés comme oracle de l’analyse de mutation. Comme nous savons que les modèles de test sont capables de déclencher les erreurs injectées dans les mutants (score de 100% à l’étape précédente), nous pouvons mesurer la capacité des contrats à détecter ces erreurs. L’amélioration des contrats consiste à créer des contrats qui traduisent la spécification le plus complètement possible.

Implantation

Spécification

Cas de test

Qualification Amélioration

Figure 5-16 - Qualification et amélioration du troisième sommet.

Les mutants qui étaient tués avec les modèles de test doivent être tués en utilisant les contrats. En revanche, les mutants équivalents ne doivent pas être tués par les contrats. Leur utilisation permet de contrôler l’exactitude des contrats qui sont complexes à écrire. Si un nouveau contrat est violé en utilisant les mutants équivalents, une analyse est nécessaire. Le contrat peut être erroné, mais il peut aussi mettre en évidence une erreur de la transformation. Dans ce cas une nouvelle itération est réalisée en utilisant ce(s) nouveau(x) contrat(s) à l’étape 2.

a- Un ensemble initial de contrats

Initialement, les contrats peuvent provenir de deux sources: ƒ Des contrats compris dans la spécification

ƒ Les contrats disponibles dans l’implantation quand le développement a été réalisé avec une méthodologie design-by-contract

Dans notre expérience, la spécification du workshop [Bézivin'05] fournit un contrat (en OCL) qui précise le domaine d’entrée de la transformation :

131 Expérimentations pour le développement d’un composant de confiance

context Class inv:

allAttributes()->size > 0 and

allAttributes()->exists(attr | attr.is_primary = true)

Nous pouvons utiliser ce contrat directement en Kermeta. Il suffit d’implémenter la méthode

allAttributes() en Kermeta.

Les opérations de l’implantation comportent également huit contrats (deux pré-conditions et six post-conditions). A ce moment, nous considérons que nous avons des contrats basiques (niveau 1) dans notre composant. La qualité (Qcont, mesurée comme défini au 5.1.3) de ces neuf contrats est de 59%. Ce résultat est représenté dans la première colonne de la figure 5-17.

93.8% 87.1% 59.3% 86.6% 92.3% 50% 60% 70% 80% 90% 100% niveau 1 9 contrats niveau 2 17 contrats niveau 3 18 contrats niveau 4 19 contrats niveau 5 21 contrats niveau de contrat Qc o n t

Figure 5-17 – Progression du score de mutation pendant l’amélioration des contrats.

b- Amélioration des contrats: introduction de contrats de sémantique comportementale

Nous procédons à l’amélioration des contrats en deux étapes. Dans ce point b-, nous traduisons la spécification en contrats et nous écrivons des contrats de sémantique comportementale (comme définis dans la section 5.1.1). Ensuite dans le point c-, nous améliorons les contrats à l’aide des mutants.

Dans un premier temps, nous avons défini deux contrats du domaine de sortie (des post- conditions). Le méta-modèle cible (figure 2-7) n’est pas assez restrictif concernant les clés des tables: il n’impose pas que les clés primaires d’une table soient parmi ses colonnes et qu’une clé étrangère ait ses colonnes parmi celles de sa table. Nous écrivons deux contrats qui prennent en compte ces contraintes (en Kermeta) :

post pkey_is_in_the_column_of_its_table is

result.table.forAll{t|t.pkey.forAll {pk|pk.container == t}}

post colunms_of_fkey_are_among_the_ones_of_its_table is

result.table.forAll{t|t.fkeys.forAll{fk|fk.cols.forAll{c|t.cols.contains(c)}}} Nous avons également défini six contrats reliant entrée et sortie (des post-conditions). Par exemple, un de ces contrats écrit en Kermeta est donné dans la figure 5-18. Il permet de vérifier que : dans une table correspondant à une classe cl, il y a des colonnes qui correspondent aux attributs cl dont les types t sont des classes persistantes (sans parent persistant) ayant des attributs primaires de type primitif.

Ces contrats de second niveau s’ajoutent aux contrats du premier niveau. En évaluant la qualité de cet ensemble de vingt-et-un contrats, nous mesurons un Qcont de 86% (comme illustré figure 5-17), soit un gain de 27%.

c- Amélioration des contrats grâce aux opérateurs de mutation

Dans un deuxième temps, nous améliorons les contrats pour renforcer leur pouvoir de détection d’erreurs. L’ensemble amélioré des contrats doit traduire au maximum la spécification pour considérer davantage d’exigences, ou de manière plus précise : soit des contrats entièrement nouveaux sont élaborés, soit les existants sont modifiés. Dans ce dernier cas, un nouveau contrat est systématiquement créé pour deux raisons :

ƒ La complexité d’une modification ne doit pas corrompre un contrat existant. Il est plus facile de créer de nouveaux contrats, comme nous avons expliqué qu’il est plus facile de créer de nouveaux modèles de test (3.3.1a-).

ƒ Chaque contrat considère une partie donnée de la spécification. De cette façon (comme expliqué au chapitre précédent), il peut être possible de réutiliser certains contrats quand la spécification est modifiée.

Comme dans la première étape (section 5.3.1), nous utilisons notre connaissance des erreurs injectées dans les mutants vivants. Exploiter ces erreurs permet de faciliter l’amélioration des contrats. En effet, nous pouvons constater avec l’exemple de la figure 5-18 (mais également dans l’Annexe A - A.3) la complexité des contrats.

133 Expérimentations pour le développement d’un composant de confiance

1 post attribute_persistent_classes is

2 // Création des colonnes correspondant aux attributs dont le type est une 3 // classe persistante transformée en table

4 inputModel.classifier

5 .select{cr| Class.isInstance(cr)}

6 .select{cs | cs.asType(Class).is_persistent}

7 .select{csp | not csp.asType(Class).allParents.exists{p | p.is_persistent}} 8 .forAll

9 {csp | // pour toute classe persistante sans parent persistant,

10 result.table.select{t|t.name == csp.name} //dans la table correspondante, 11 .exists{tn | csp.asType(Class).attrs

12 .select{at | Class.isInstance(at.type)}

13 // les attributs dont le type est une classe 14 .select{atc|atc.type.asType(Class).is_persistent} 15 //qui est persistante

16 .select{atcp | not atcp.type.asType(Class).allParents

17 .exists{p | p.is_persistent}}

18 // mais sans parent persistant

19 .forAll

20 {atcpwp| // (atcpwp est un attribut don’t le type est une classe 21 // persistante sans parent persistant

22 atcpwp.type.asType(Class).attrs

23 .forAll

24 {atcpta| //pour tous les attributs de ce type 25 if PrimitiveDataType.isInstance(atcpta.type) 26 //qui sont de type primitif

27 and atcpta.is_primary // et qui sont primaires

28 then

29 tn.cols.select{ctn |

30 ctn.name == atcpwp.name+"_"+atcpta.name

31 // alors il y a une colonne du nom de cette

32 // attribut + « _ » + le nom de l’attribut

33 // primaire de type primitif

34 and ctn.type == atcpta.type.name

35 // et du type de ce dernier attribut,

36 //to be improved

37 }.size==1 //cette colonne est l’unique correpondante

38 else true end

39 }

40 }

41 }

42 }

Figure 5-18 - Un exemple de contrat de sémantique comportementale

Dans l’expérimentation, nous avons, par exemple, essayé de tuer un mutant qui n’associe pas les colonnes à une clé étrangère (FKey). Nous avons créé un contrat à partir de celui de la figure 5-18 en vérifiant que la colonne considérée ctn est une des colonnes d’une fkey de la table tn. C’est une amélioration qui se traduit par le code de la figure 5-19. Il remplace le commentaire « //to be improved » à la ligne 36 de la figure 5-18 pour créer un nouveau

contrat. L’opérateur de mutation supprime la création d’une relation entre une fkey et ses colonnes, donc le contrat amélioré vérifie l’existence de cette relation.

and tn.fkeys.exists{ftn | ftn.cols.contains(ctn)}

Figure 5-19 - Amélioration d'un contrat

En appliquant cette méthode, nous améliorons la valeur Qcont de l’ensemble des contrats du composant. Nous l’illustrons dans les troisième, quatrième, cinquième colonnes de la figure 5-17. Cette fois, nous obtenons un gain pour Qcont de 7%.