• Aucun résultat trouvé

Chapitre 2. Test et développement formel

3.6.1 Analyse préliminaire

Nous rappelons dans la Figure 3.10 l’architecture du développement de l’exemple du Triangle. MAIN_INTERFACE.mch MAIN_INTERFACE_1.imp TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp TRIANGLE.mch TRIANGLE_1.ref TRIANGLE_2.imp OUTILS.mch OUTILS_1.imp BASIC_TYPE_DE_TRIANGLE.mch IMPORTS REFINES SEES SEES SEES SEES IMPORTS IMPORTS IMPORTS REFINES REFINES REFINES REFINES

Figure 3.10. Architecture du développement de l’exemple du Triangle

Le composant racine de l’architecture est la MACHINEMAIN_INTERFACE qui offre

une opération main. Nous donnons, dans la Figure 3.11, le texte de cette opération et son implémentation dans le composant MAIN_INTERFACE_1.imp. Dans le composant

racine, l’opération main n’exprime qu’une vue boîte noire du programme (substitution skip). A ce niveau rien ne peut être observé ni commandé. L’implémentation de cette opération séquence les trois phases d’acquisition de données, de calcul et d’affichage des résultats : elle demande à l’utilisateur d’entrer trois nombres entiers ayant une valeur entre 0 et MAXINT, calcule la validité et le type de triangle par un appel à l’opération Classe_Triangle, et affiche le résultat. Comme nous l’avons expliqué dans le paragraphe 3.5.3, le test de ce système peut se

concentrer sur la phase de calcul, les phases d’acquisition et d’affichage étant simulées par des bouchons. L’opération Classe_Triangle étant spécifiée dans le composant TYPE_TRIANGLE, nous allons donc tester le sous-système ayant ce

composant pour racine.

main Í skip main Í BEGIN

VAR mint, c1, c2, c3, tt IN mint ← SQRT (MAXINT);

STRING_WRITE ("Entrez un entier :"); c1 ← INTERVAL_READ (0, mint); STRING_WRITE ("Entrez un entier :"); c2 ← INTERVAL_READ (0, mint); STRING_WRITE ("Entrez un entier :"); c3 ← INTERVAL_READ (0, mint); tt ← Classe_Triangle (c1, c2, c3);

STRING_WRITE ("On a un triangle du type :"); TYPE_DE_TRIANGLE_WRITE (tt);

END

END

Figure 3.11. Spécification de l’opération main dans le composant MAIN_INTERFACE.mch et son implémentation dans le composant MAIN_INTERFACE_1.imp

Pour cela, un moniteur de test doit être construit sur le modèle de l’implémentation de main, les interfaces utilisées par ce moniteur (acquisition des entrées et observation des sorties) étant appropriées à l’environnement d’animation. Le moniteur importe le modèle déplié sous test de racine TYPE_TRIANGLE, pour pouvoir implémenter les

séquences de test sur ce modèle. Il doit également importer un bouchon simulant le composant vu BASIC_TYPE_DE_TRIANGLE, qui définit : 1) l’ensemble TYPE_DE_TRIANGLE = {ISOCELE, EQUILATERAL, SCALENE, RECTANGLE, INVALIDE}, et

2) les opérations de lecture et d’écriture concernant les éléments de cet ensemble (par exemple, l’opération TYPE_DE_TRIANGLE_WRITE).

Nous allons maintenant examiner le sous-ensemble du développement à partir du composant TYPE_TRIANGLE, pour identifier les étapes auxquelles des modèles

testables sont obtenus.

3.6.2 Identification des étapes de développement

En suivant les conditions architecturales définies dans les paragraphes 3.3.2 et 3.3.3, les différentes étapes de ce développement peuvent être identifiées de manière systématique. Dans la Figure 3.12, nous montrons la hiérarchie des modèles correspondants. Chaque modèle est constitué d’un ensemble de composants dont la mise à plat résulte en une machine abstraite. Ainsi, le modèle de plus haut niveau est la MACHINE TYPE_TRIANGLE. Le Modèle 2 contient en plus le raffinement de cette

MACHINE, c’est-à-dire l’IMPLEMENTATION TYPE_TRIANGLE_1, ainsi que les

composants importés TRIANGLE et OUTILS. Selon les conditions architecturales, le

Modèle 2 est un raffinement du Modèle 1, et est raffiné par l’implémentation finale. Dans cet exemple, il n’y a pas de lien SEES interne au sous-système considéré, et donc

pas d’ordre imposé pour le raffinement des différentes branches du développement. Ainsi, n’importe lequel des Modèles 3 et 4 peut être pris comme successeur du Modèle 2, selon que l’on descende d’un niveau de raffinement à partir du composant

TRIANGLE ou du composant OUTILS. Notons que la Figure 3.12 résulte de l’analyse a

posteriori d’une architecture complète, allant jusqu’à l’implémentation finale. Une analyse similaire pourrait être conduite en cours de développement, donnant par exemple l’identification des Modèles 1 à 3.

TYPE_TRIANGLE.mch TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp OUTILS.mch OUTILS_1.imp TRIANGLE.mch IMPORTS REFINES REFINES IMPORTS TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp OUTILS.mch OUTILS_1.imp TRIANGLE.mch TRIANGLE_1.ref IMPORTS REFINES REFINES REFINES IMPORTS TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp OUTILS.mch TRIANGLE.mch TRIANGLE_1.ref IMPORTS REFINES REFINES IMPORTS TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp OUTILS.mch TRIANGLE.mch TRIANGLE_1.ref TRIANGLE_2.imp REFINES IMPORTS REFINES REFINES IMPORTS TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp OUTILS.mch TRIANGLE.mch IMPORTS REFINES IMPORTS TYPE_TRIANGLE.mch TYPE_TRIANGLE_1.imp OUTILS.mch OUTILS_1.imp TRIANGLE.mch TRIANGLE_1.ref TRIANGLE_2.imp REFINES IMPORTS REFINES REFINES REFINES IMPORTS Modèle 1 Modèle 2 Modèle 7 Modèle 6 Modèle 5 Modèle 4 Modèle 3 × × × × × × × ×

Figure 3.12. Modèles obtenus aux étapes de développement du sous-système de racine TYPE_TRIANGLE

Une fois qu’une hiérarchie de modèles est obtenue, se pose le choix du modèle à tester. Ce choix peut être guidé par une analyse de traçabilité vis-à-vis du cahier des charges, pour déterminer l’étape à laquelle tous les besoins de l’utilisateur sont censé avoir été pris en compte. Pour l’exemple du Triangle, une telle analyse de traçabilité a été présentée dans le chapitre 2 de ce mémoire (dans le paragraphe 2.5.3). Elle montre que la spécification complète du problème n’est obtenue qu’à la fin du développement, c’est-à-dire dans le Modèle 7. Ainsi, nous savons déjà que tous les modèles sont incomplets vis-à-vis des besoins du cahier des charges. Dans ce cas, la vérification externe est réalisée par test du code final, qui constitue une version compilée du modèle le plus concret.

Nous allons pourtant considérer, dans le paragraphe suivant, le test de chacun des modèles B de la hiérarchie. Ceci nous permettra d’illustrer comment se traduit l’imprécision de ces modèles en termes de réponses à des séquences de test. Nous verrons également comment la relation de raffinement est exploitée pour ne rejouer sur un modèle, qu’un sous-ensemble des séquences de test appliquées à ses abstractions.