3-real10-11 (1)

107
Annie Culet OMGL2 OMGL2 Conception Conception logiciel logiciel Etape Etape Codage Codage IHM IHM Donn Donn é é es es Logiciel Logiciel Tests Tests

Upload: jules-obadiajr

Post on 05-Jul-2015

67 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 3-Real10-11 (1)

Annie Culet

OMGL2OMGL2

Conception Conception logiciellogiciel

EtapeEtape CodageCodage

IHM IHM

DonnDonnééeses

LogicielLogiciel

TestsTests

Page 2: 3-Real10-11 (1)

Etape 3Codage

� La phase de codage

Traduction de la conception dans un langage de programmation

Exécution des tests

� Résultat

Des sources commentés, commandes de compilation, exécution ..

Résultats des tests

Page 3: 3-Real10-11 (1)

La réalisation Annie Culet 3

Etape 3 : codage - démarche

Choix du langage de programmation et de la bibliothèque graphique :

Ada / GtkAda

Choix de la méthode de gestion de la persistance des données :

Outil de mapping typeAda/ relationnel : Mill

Choix du logiciel de test : framework AUnit

Réalisation :

L’IHM

Code des procédures "charge" et handler des modules IHM

Le noyau fonctionnel

Schéma relationnel des données

Code des procédures de la couche application du noyau fonctionnel

Tests fonctionnels unitaires

Page 4: 3-Real10-11 (1)

La réalisation Annie Culet 4

Bonnes pratiques de programmation

Il est indispensable de :

� comprendre son propre code

� en cours d'écriture

� après un mois (!)

� être compris par les autres développeurs

� changement d'équipe, maintenance, ...

Que fait ce programme ? Exemple tiré de http://www.labri.fr/~marlet

int a[1817];main(z,p,q,r){for

(p=80;q+p-80;p-=2*a[p])for(z=9;z--;)q=3&(r=time(0)+r*57)/

7,q=q?q-1?q-2?1-p%79?-1:0:p%79-

77?1:0:p<1659?79:0:p>158?-79:0,q?!a

[p+q*2]?a[p+=a[p+=q]=q]=q:0:0;for(;q++-1817;)printf(q%79?"%c":"%

c\n"," #"[!a[q-1]]);}

Page 5: 3-Real10-11 (1)

La réalisation Annie Culet 5

Bonnes pratiquesNommage : choisir des noms explicites, utliser des conventions de nommage

meilleure lisibilité du code,recherche facilitée, distingue l’élément désigné.

� Variables

nomAuteur, refOuvrage et non a, xentNomPays et non entry1, nom

� Types

tnomAuteur et non ch30

� Modules

p_ajouterOuvrage et non CU7

� Procédures, fonctions

consulterTousAuteurs (…) et non consult (…)

� Exceptions

ExPaysExistant et non e1

Page 6: 3-Real10-11 (1)

La réalisation Annie Culet 6

Bonnes pratiquesStructuration du code et homogénéité

modules utilitaires, procédures privées, …. (pas de code redondant)

homogénéité d’un style dans l’utilisation des structures de contrôles,

règles de style et d’indentation, … (cf. cours algo/prog)

Commentaires

Les commentaires doivent être ...

� nombreuxil n'y en a jamais assez

� uniquesduplication → incohérence, problème de maintenance

� pertinentspas de commentaire « affectation de la variable x à zéro » pour « x = 0; »

� au plus près de la chose commentéesystématiquement mis à jour

Page 7: 3-Real10-11 (1)

La réalisation Annie Culet 7

Bonnes pratiquesUtilisation d’un environnement de développement

� IDE environnement de développement intégré

� gestionnaire de versions

Exemples en Ada :

Gnat Programming Studio (Unix)

Eclipse (plug-in pour Ada),

AdaGide (Windows)

Page 8: 3-Real10-11 (1)

Réalisation IHM Annie Culet 8

Réalisation de l’IHM� Notion de programmation événementielle

� Présentation de la bibliothèque graphique GtkAda

� Codage de l’interface

� description des fenêtres en XML

� désignation des composants de l’IHM dans le code

� codage des procédures handler

� conversion de types

Page 9: 3-Real10-11 (1)

Réalisation IHM Annie Culet 9

Programmation événementielle

Application interactive

� Programmation événementielle : l’utilisateur a le contrôle

� une action de l'utilisateur sur un composant graphique déclenche un événement

� exemples d’événement : un clic sur un bouton de commande, une saisie dans une

zone de texte, une sélection dans une liste, un choix dans une case à cocher…

� les événements sont captés par le système d'exploitation puis pris en charge par la

boucle de gestion des événements

� si une procédure spécifique (handler, callback, procédure de rappel) est associée à

un événement, elle est alors exécutée

Exemple : le fait de cliquer sur le « Bouton A » va déclencher l'évènement « clicked »

associé à « Bouton A ». Le programmeur définit pour chacun des composants qu'il utilise,

les évènements qu’il veut gérer pour ce composant, et donc les procédures associées à la

gestion de cet évènement pour ce composant.

Page 10: 3-Real10-11 (1)

Réalisation IHM Annie Culet 10

Utilisation de la bibliothèque graphique GtkAda

� GtkAda : bibliothèque graphique

permet de réaliser des interfaces graphiques en Ada.

construite sur la bibliothèque graphique GTK+ (Gimp ToolKit, libre)

� GTK+ existe sur plusieurs plates-formes (UNIX, Windows)

� GTK+ est utilisable avec plusieurs langages de programmation

(C, C++, Ada, Perl, Python, PHP … )

� Intégrée avec un constructeur d’interface graphique Glade

� Glade sauvegarde un projet dans un fichier XML (.glade) contenant une description de

l'interface et les procédures à appeler pour traiter les différents signaux

� La bibliothèque libglade permet de créer et afficher dynamiquement les composants

à partir d’un fichier de définitions XML

� Glade.XML est le module de liaison à la bibliothèque libglade

Page 11: 3-Real10-11 (1)

Réalisation IHM Annie Culet 11

� XML : eXtensible Markup Language (Langage à balises extensible)

� Norme permettant de définir un format d'échange de données structurées selon les

besoins de l'utilisateur (standard du World Wide Web Consortium)

� Les données sont indépendantes de l'affichage.

� Un document XML est composé de balises et de texte libre.

� Un document XML peut se représenter sous la forme d'une arborescence d'éléments

<?xml version="1.0" encoding="ISO-8859-1"?><annuaire>

<personne><nom>Strummer</nom><prenom>Joe</prenom>

</personne><personne>

<nom>Cantat</nom><prenom>Bertrand</prenom>

</personne></annuaire>

XML

Page 12: 3-Real10-11 (1)

Réalisation IHM Annie Culet 12

<?xml version="1.0" encoding="UTF-8" standalone="no"?><glade-interface>

<widget class="GtkWindow" id="oneWindow" ><property name="visible">True</property><property name="title" translatable="yes">maFenetre </property><child>

<widget class="GtkVBox" id="vbox1"><child>

<widget class="GtkHBox" id="hbox1"><child>

<widget class="GtkLabel" id="label1" ><property name="label" translatable="yes">Nom de fam ille</property>

</widget></child>

<child><widget class="GtkEntry" id="entry_nomFamille" >

<property name="visible">True</property></widget>

</child></widget>

</child><child>

<widget class="GtkHBox" id="hbox2"><child>

<widget class="GtkButton" id="button_valider" ><property name="label" translatable="yes">Valider</ property><signal name="clicked" handler="on_button_valider_clicked" />

</widget>...

</child></widget>

</child></widget>

</child></widget>

</glade-interface>

balise et fermeture de balise

<mot clé …> </mot clé>

propriété : attribut = "valeur"class ���� type du composantid ���� identificateur du composanthandler ���� identificateur de la procédure

Extrait d’un fichier XML généré par Glade

Page 13: 3-Real10-11 (1)

Réalisation IHM Annie Culet 13

Description de l’interface� La description d’un composant graphique est introduite par la balise <widget

� Lorsqu’un composant en contient d’autres, ceux-ci sont placés dans un bloc <child

� Chaque composant graphique est défini par :

une classe (son type, par exemple GtkWindow, GtkButton, ...)

un id (son identificateur, qui permet d'y accéder par la suite)

<widget class="GtkEntry" id="entry_nomFamille">

un certain nombre de propriétés qui dépendent du type du composant

<property name="visible">True</property> indique que la fenêtre est visible

� La balise <signal introduit le type du signal émis qui déclenchera la procédure dont

l’identificateur est donné.

<signal name="clicked" handler="on_button_valider_clicked"/>

Page 14: 3-Real10-11 (1)

Réalisation IHM Annie Culet 14

usr/share/ada/adainclude/gtkada2/glade.XML.ads

-- This package is a binding to the libglade library that provides routines

-- to create widgets dynamically from an XML definition file.

with … ;with Gtk.Widget; use Gtk.Widget;

package Glade.XML is

type Glade_XML_Record is new Glib.Object.GObject_Record with private;type Glade_XML is access all Glade_XML_Record'Class;

procedure Gtk_New(XML : out Glade_XML;Fname : String;Root : String := "";Domain : String := "");

-- Create a new GladeXML object (and the corresponding widgets) from the XML file Fname.

-- Optionally it will only build the interface from the widget node Root (if it is not empty)

-- Domain, if not null, is the international domain to use for string translation.

Page 15: 3-Real10-11 (1)

Réalisation IHM Annie Culet 15

usr/share/ada/adainclude/gtkada2/glade.XML.ads

procedure Signal_Connect(XML : access Glade_XML_Record;Handlername : String;Func : System.Address;User_Data : System.Address);

function Get_Widget

(XML : access Glade_XML_Record; Name : String) return Gtk_Widget;

-- This function is used to get the Gtk_Widget corresponding to name in the interface description.

-- You would use this if you have to do anything to the widget after loading.

function Get_Widget_Name

(Widget : access Gtk_Widget_Record'Class) return String;

….

Page 16: 3-Real10-11 (1)

Réalisation IHM Annie Culet 16

Programme principal "type"

with Gtk.Main; with Glade.XML;

procedure start is

xml : Glade_XML ; -- variable de type Glade_XML

begin

-- Initialisation de variables d’environnement

Gtk.Main.Set_Locale;-- Initialisation de Gtk Gtk.Main.Init; --Chargement de la description complète de l’interface à partir du fichier XML et affichage

Glade.XML.Gtk_New (xml, " monFichier.glade");-- Lancement de la boucle évènementielle de Gtk

Gtk.Main.Main;

end start;

Page 17: 3-Real10-11 (1)

Réalisation IHM Annie Culet 17

"Chargement" d’une description de fenêtre

� "Chargement" de la description d’une fenêtre à partir de son id dans le fichier XML

xml : Glade_XML ; -- variable de type Glade_XML

Glade.XML.Gtk_New (xml, "fichier.glade", "oneWindow") ;<widget class="GtkWindow" id="oneWindow">

</widget>

<widget class="GtkWindow" id=“anOtherWindow">

</widget>

� " Récupération" d’un composant de la fenêtre à partir de son id dans le fichier XML avec

conversion de type

entNom : Gtk_Gentry; -- variable de type Gtk_Gentry

entNom := Gtk_Entry (Glade.XML.Get_Widget (xml, "entry_nomFamille");

<widget class="GtkEntry" id="entry_nomFamille">

paramètre en sortie

paramètre en entrée

Page 18: 3-Real10-11 (1)

Réalisation IHM Annie Culet 18

Association d’une procédure Handler

� Association d’une procédure Handler désignée par son identificateur dans la description de l’interface à une procédure dans un programme :

Glade.XML.signal_connect (xml, "on_button_valider_clicked", procTraite’address,

System. null_address);

<signal name="clicked" handler="on_button_valider_clicked"/>

procedure procTraite (widget : access Gtk_Widget_Record’Class) isbegin-- traitement à effectuer sur émission du signal

end procTraite;

Page 19: 3-Real10-11 (1)

Réalisation IHM Annie Culet 19

with Glib.Object;with Glib.Properties;with Glib.GSlist;with Gtkada.Types;

package Gtk.Object is

type Gtk_Object_Record is new Glib.Object.GObject_Record with private;type Gtk_Object is access all Gtk_Object_Record'Class;

procedure Destroy (Object : access Gtk_Object_Record);

-- Destroy the object.

-- The object is then unref-ed, and the memory associated with the object is freed.

-- In most cases, only toplevel widgets (windows) require explicit destruction

-- because when you destroy a toplevel its children will be destroyed as well.

usr/share/ada/adainclude/gtkada2/Gtk.Object.ads

Page 20: 3-Real10-11 (1)

Réalisation IHM Annie Culet 20

usr/share/ada/adainclude/gtkada2/Gtk.Widget.ads….

with Gtk.Enums;with Gtk.Object;

with Gtk.Style;

package Gtk.Widget istype Gtk_Widget_Record is new Object.Gtk_Object_Record with private;type Gtk_Widget is access all Gtk_Widget_Record'Class;

procedure Show (Widget : access Gtk_Widget_Record);-- Schedule the widget to be displayed on the screen when its parent is also shown

procedure Hide (Widget : access Gtk_Widget_Record);-- Hide the widget from the screen

-- If Widget was visible, it is immediately hidden.

procedure Show_All (Widget : access Gtk_Widget_Record);-- Show Widget and all its children recursively.

procedure Hide_All (Widget : access Gtk_Widget_Record);-- Hide Widget and all its children.

procedure Set_Sensitive (Widget : access Gtk_Widget_Record; Sensitive : Boolean := True);-- Modify the sensitivity of the widget.

-- An insensitive widget is generally grayed out, and can not be activated.

Page 21: 3-Real10-11 (1)

Réalisation IHM Annie Culet 21

with Gtk.Widget;

package Gtk.Editable is

type Gtk_Editable_Record is new Gtk.Widget.Gtk_Widget_Record with private;type Gtk_Editable is access all Gtk_Editable_Record'Class;

-- Gtk_Editable is now an interface, not an object

procedure Insert_Text (Editable : access Gtk_Editable_Record; New_Text : UTF8_String; Position : in out Gint);-- Insert the given string at the given position.

-- Position is set to the new cursor position. If Position is -1, the text is appended at the end.

procedure Delete_Text (Editable : access Gtk_Editable_Record; Start_Pos : Gint := 0; End_Pos : Gint := -1);-- Delete the characters from Start_Pos to End_Pos.

-- If End_Pos is negative, the characters are deleted from Start_Pos to the end of the text.

procedure Set_Editable (Widget : access Gtk_Editable_Record; Editable : Boolean := True);

usr/share/ada/adainclude/gtkada2/Gtk.Editable.ads

Page 22: 3-Real10-11 (1)

Réalisation IHM Annie Culet 22

with Glib.Properties;with Gtk.Editable;

with Gtk.Entry_Completion; use Gtk.Entry_Completion;with Pango.Layout;

package Gtk.GEntry is

type Gtk_Entry_Record is new Gtk.Editable.Gtk_Editable_Record with private;-- Gtk_Entry is actually a child of Gtk_Widget, and implements the

-- Gtk_Editable interface, but GtkAda does not support yet interfaces,

type Gtk_Entry is access all Gtk_Entry_Record'Class;subtype Gtk_GEntry is Gtk_Entry;

procedure Set_Text (The_Entry : access Gtk_Entry_Record; Text : UTF8_String);

function Get_Text (The_Entry : access Gtk_Entry_Record) return UTF8_String;

-- Modify the text in the entry.

-- The text is cut at the maximum length that was set when the entry was created.

-- The text replaces the current contents.

procedure Set_Max_Length (The_Entry : access Gtk_Entry_Record; Max : Gint);

-- Set the maximum length for the text. The current text is truncated if needed.

usr/share/ada/adainclude/gtkada2/Gtk.Gentry.ads

Page 23: 3-Real10-11 (1)

Conception Logiciel Annie Culet 23

Architecture d’un logiciel interactif

Adaptateur des données

Ajuste les différences de modélisation entre les données de la présentation et celles du noyau

fonctionnel (conversion de type, interprétation de cases à cocher, boutons radio, …)

Couche IHM

Noyau Fonctionnel

acquisition des données en provenance de l’utilisateur

restitution de données vers l’utilisateur

appel des procédures du noyau fonctionnel

Présentation et dialogue

Adaptateur des données

récupération des résultatsdonnées converties aux types de données du langage

données au format des composants de la fenêtre

données au format des types de données du langage

données converties au format des composants de la fenêtre

Page 24: 3-Real10-11 (1)

La réalisation Annie Culet 24

Adaptateur de données� Module de conversion de type : p_conversion (fourni localement)

� une fonction : empty

-- teste si une chaîne UTF8 est vide ou non

� des procédures : to_ada_type

-- conversion d’une chaîne UTF8 vers un type Ada

� des fonctions : to_string

-- conversion un type numérique non contraint et date en chaîne UTF8

+ modules génériques pour les conversions concernant

les numériques contraints et les énumérés

avec des procédures/fonctions : to_ada_type et to_string

� une procédure to_ada_type :

� lève l’exception ExConversion si le type en sortie n’est pas conforme au type Ada attendu,

� affiche un message d’erreur dans une boîte de dialogue.

Page 25: 3-Real10-11 (1)

Réalisation IHM Annie Culet 25

Module de conversion de typepackage p_Conversion is

-- teste si une chaîne est vide ou non

function empty (entree : UTF8_String) return boolean;

-- effectue une conversion d’une chaîne vers un type Ada

(chaîne ou numérique non contraint)

-- si le type en sortie n’est pas conforme au type Ada attendu, affiche un message d’erreur et lève

l’exception ExConversion

procedure to_ada_type (entree : UTF8_String; sortie : out integer) ;

procedure to_ada_type (entree : UTF8_String; sortie : out float) ;

procedure to_ada_type (entree : UTF8_String; sortie : out string );

ExConversion : exception ;

-- convertit un type numérique non contraint en chaîne

function to_string (item : float) return string;

function to_string (item : integer) return string;

Page 26: 3-Real10-11 (1)

Réalisation IHM Annie Culet 26

Module de conversion de type

-- modules génériques pour les conversions concernant les numériques contraints et les énumérés

-- si le type en sortie des procédures to_ada_type n’est pas conforme au type Ada attendu, affiche

un message d’erreur et lève l’exception ExConversion

generic

type entier is range <> ;

package P_Entier is

procedure to_ada_type (entree : UTF8_String; sortie : out entier );

ExConversion : exception ;

function to_string (item : entier) return string;

end P_Entier;

Page 27: 3-Real10-11 (1)

Réalisation IHM Annie Culet 27

Module de conversion de typegeneric

type reel is digits <> ;

package P_Reel is

procedure to_ada_type (entree : UTF8_String; sortie : out reel );

ExConversion : exception ;

function to_string (item : reel) return string;

end P_Reel;

---------------------------------------------------------------------------------------------------------------------------

generic

type t_enum is (<>);

package P_Enum is

procedure to_ada_type (entree : UTF8_String; sortie : out t_enum );

ExConversion : exception ;

function to_string (item : t_enum) return string;

end P_Enum;

Page 28: 3-Real10-11 (1)

Conception Logiciel Annie Culet 28

Contrôles réalisés dans l’IHM

� A l’issue d’une saisie, les contrôles de type et de présence de données obligatoires

sont effectués dans la couche IHM avant tout appel d’une procédure du NF.

Les types des paramètres d’une procédure du NF sont donc vérifiés avant son appel.

� Contrôle de présence pour une donnée obligatoire

Ex. vérification qu’une zone d’entrée n’est pas vide

� Contrôle du type d’une donnée saisie

si l’adaptateur n’arrive pas à convertir le contenu d’une zone d’entrée, un

élément d’une liste ou d’une table au type de la donnée correspondant dans le

langage de programmation (chaîne d’une longueur donnée, entier, réel,

énuméré, …), il y a une erreur de type.

Page 29: 3-Real10-11 (1)

Réalisation IHM Annie Culet 29

Codage de l’interfaceModule fenêtre

� Choisir la modalité de la fenêtre� Définir une variable par composant manipulé

� Lorsqu’une fenêtre est composée de plusieurs régions, pour focaliser le dialogue dans une région, les autres régions doivent être rendues inaccessibles

Set_Sensitive (butEnregistrer, false)

Set_Editable (entNom, false)

Protection contre les erreurs

Page 30: 3-Real10-11 (1)

Réalisation IHM Annie Culet 30

Code des procédures handler

charge (…)enregistrerAdherent()…

p_window_enregAdherentConversion Chaînes /types du langageException

ExConversion

p_conversionCouche IHM

Noyau FonctionnelCouche application

bibliothèque graphiqueGtkAda

creerAdherent ( adh : tAdhérent) ;

p_application

utilise

légendepropage exception

Interface

creerAdhérent (d adh : tAdhérent) ;

{ } �{ le numéro de l’adhérent est généré. L’adhérent adh est créé sans emprunt}

Enregistrer/générer numAdhérent

et créer adhérent

Enregistrer un adhérent

Annuler

OkB. Confirm

F. EnregAdh

Interface p_window_enregAdherent

charge (…)enregistrerAdherent(…){ } �{la boîte de dialogue de confirmation de la création de l’adhérent est affichée; la fenêtre “EnregAdh“ est fermée }annulerOperation(..) { } �{la fenêtre “EnregAdh“ est fermée}

Page 31: 3-Real10-11 (1)

Réalisation IHM Annie Culet 31

Code des procédures handler

procedure enregistreAdherent (…) is

1. – vérif. présence infos obligatoires, récupération des valeurs saisies,conversion vers types Ada du modèle de données

adh : tAdherent;

if empty (get_text(entNom)) then rep := Message_Dialog (« le nom est obligatoire »); else ….p_conversion.to_ada_type(get_text(entNom), adh.nomAdherent)); ….if get_active(radiobutAdulte) then adhVal.categorie := adulte; ….

2. -- appel de la procédure du noyau fonctionnel. Le type adhVal est correct. Message de confirmation.

creerAdherent (adhVal , adhIdf) ;rep := Message_Dialog (« Confirmation enregistrement adhérent » & adhVal.numAdherent);destroy (FenEnregAdherent); -- destruction de la fenêtre

3. -- traitement des exceptions

when ExConversion => return;when ExopFatal => rep := Message_Dialog (« Problème sur la base »);

Page 32: 3-Real10-11 (1)

Réalisation IHM Annie Culet 32

Code des procédures handler

charge (…)rechercherAdherent()modidierAdherent()

p_FenModifCoordAdherent

Couche IHM

Noyau FonctionnelCouche application

Modifier coordonnées adhérent

Annuler

Rechercher

/ consulter adhérent

Enregistrer / modifier adhérent

Annuler

Ok

[non trouvé]Ok

F. ModifAdhrégion 1

F. ModifAdhrégion 2

B. Confirm

B.Erreur

[trouvé]

Interface

consulterAdhérent (d n : tnumAdhérent; r adh : tAdhérent);

{ } �{l’adhérent n est consulté et les informations relatives à l’adhérent sont retournées dans adh}Exception : AdhérentNonTrouvé {l’adhérent n n’existe pas}

modifierAdhérent (d n : tnumAdhérent; d adh : tAdhérent);

{ } �{les coordonnées de l’adhérent n sont modifiées et sont enregistrées}

retourne résultat

utilise

légende

propage exception

consulterAdherent (n : …) : tAdherent;Exception ExAdherentNonTrouve

modifierAdherent (adh : tAdherent)

p_application

Page 33: 3-Real10-11 (1)

Réalisation IHM Annie Culet 33

Code des procédures handler

Procedure on_buttonRechercher_clicked (…) is

1. -- vérif. présence du numéro, récupération de la valeur saisie et conversion au type Ada du modèle de données

-- les boutons Enregistrer/Annuler ne doivent pas être activables, ….

2. -- appel de la procédure du noyau fonctionnel. Le type adhIdf est correct.

consulterAdherent (adhIdf, adhVal ) ;

3. -– affichage des valeurs résultat dans la région 2 de la fenêtre-- les boutons Rechercher/Annuler ne doivent pas être activables, …. Le nom est non modifiable.

set_text (entNom, adhVal.nomAdherent); -- pas de conversion puisque le nom est une chaîne

4. -- traitement des exceptions

when ExConversion => return; when ExAdherentNonTrouve => rep := Message_Dialog (« Adhérent non trouvé »); when ExopFatal => rep := Message_Dialog (« Problème sur la base »);

Spécification{ } �{les informations relatives à l’adhérent sont affichées dans la fenêtre}

Page 34: 3-Real10-11 (1)

Réalisation IHM Annie Culet 34

Code des procédures handler

Procedure on_buttonEnregistrer_clicked (…) is

1. -- récupération de la nouvelle adresse saisie et conversion au type Ada du modèle de données

2. -- appel de la procédure du noyau fonctionnel. Message de confirmation. Destruction de la fenêtre

modifierAdherent (adhIdf, adhVal ) ; ……

3. -- traitement des exceptions

when ExConversion => return; when ExopFatal => rep := Message_Dialog (« Problème sur la base »);

Spécification{ } �{les nouvelles informations relatives à l’adhérent sont enregistrées}

Page 35: 3-Real10-11 (1)

Réalisation IHM Annie Culet 35

Code des procédures handlerInterface couche ApplicationconsulterOuvrage(ouvIdf : in tOuvrageIdf ;

ouvVal : out tOuvrageVal ; autVal : out tautVal);Exception : ExOuvrageNonTrouveException : ExOuvrageDisponible

consulterEmprunt (empIdf : in tEmpruntIdf ;empVal : out tEmpruntVal);

type tOuvrageVal is recordréfOuvrage : trefOuvrage;…auteur : tAuteurIdf;empruntOuvrage : tEmpruntIdf := empruntNul;

end record;

Procedure on_buttonRechercher_clicked (…) is

1. -- récupération de la valeur saisie dans la fenêtre et conversion

2. -- appel au noyau fonctionnel.

consulterOuvrage (ouvIdf, ouvVal , autVal) ;consulterEmprunt (ouvVal.empruntOuvrage, empVal);

3. -– affichage des valeurs résultat affiche_InfosOuvrageAuteur; -- procédure privéeaffiche_InfosEmprunt; -- procédure privée

4. -- traitement des exceptions

when ExOuvrageNonTrouve => rep := Message_Dialog (« Ouvrage non trouvé »);when ExOuvrageDisponible => affiche_InfosOuvrageAuteur;

set_text (entDateEmprunt, « Ouvrage disponible » ); -- + les autres

Spécification{ } �{les infos sur l’ouvrage, son auteur et éventuellement son emprunt sont affichées dans la fenêtre}

Page 36: 3-Real10-11 (1)

La réalisation Annie Culet 36

Conception des données� Solution retenue :

� les données sont stockées dans une base de données relationnelle

� Dans ce contexte : détermination du schéma relationnel de données

On applique les « règles » de traduction Diagrammes de classes / Schéma relationnel

Le schéma relationnel obtenu doit préciser :

� les clés primaires

� les clés étrangères

Il faut également préciser :

� le caractère « obligatoire » ou non des attributs

� toutes les contraintes d’intégrité du diagramme de classes non prises en compte

par le schéma relationnel

Page 37: 3-Real10-11 (1)

Conception Données Annie Culet 37

à partir d’un diagramme de classes …

réfOuvrage : ChainetitreOuvrage : ChainegenreOuvrage : Enum {roman, policier, SF, documentaire, théâtre, poésie, BD }dateParution : Date

Ouvrage

nomAuteur : ChaineprénomAuteur : ChainenationalitéAuteur : Chaine

Auteur

auteur

publication 1..1

1..*

numAdhérent : ChainenomAdhérent : ChaineadresseAdhérent : Chainecatégorie : Enum {jeune, adulte}

Adhérent

dateEmprunt :Date

Emprunt0..4

0..1

emprunt

emprunteur

{taille(numAdhérent) ≤ 5 et unique}

{concat(nomAuteur, prénomAuteur) unique}

{taille(réfOuvrage) ≤ 6 et unique} Gestion d’une bibliothèque

Page 38: 3-Real10-11 (1)

La réalisation Annie Culet 38

Passage du diagramme de classes au relationnel

� R0 : Chaque classe C devient une relation RC dont :

les attributs sont les attributs monovalués de la classe C,

la clé de RC est l’attribut (ou groupe d’attributs) marqué par la contrainte {unique} ou un nouvel attribut.

nomAuteurprénomAuteurnationalitéAuteur

Auteur

{concat(nomAuteur, prénomAuteur) unique}

AUTEUR(nomAuteur, prénomAuteur, nationalité)

minutesRetardraison

Retard RETARD(cléRetard, minutesRetard, raison)

Page 39: 3-Real10-11 (1)

La réalisation Annie Culet 39

Passage du diagramme de classes au relationnel

� R1 : un attribut multivalué d’une classe C devient une relation dont :

les attributs sont l’attribut multivalué de la classe C et la clé de la relation RC représentant la classe C qui est clé étrangère,

la clé de cette relation est l’ensemble des 2 attributs.

Personne

numSécu {unique}nomtelPersonnel [1..2]

PERSONNE(numSécu, nom)TELPERSONNE(#numSécu, telPersonnel)

Page 40: 3-Real10-11 (1)

La réalisation Annie Culet 40

Passage du diagramme de classes au relationnel

� R2 : une association dont l’un des rôles est de multiplicité 1 détermine une clé étrangère dans la relation RC représentant la classe C associée au rôle inverse.

Les attributs de la classe association deviennent attributs de cette relation RC.

nInsee {unique}nomage

Personne

nomService {unique}batiment

Service

service

employé 1

1..*

PERSONNE(nInsee, nom, age, # nomService, dateEmbauche)SERVICE(nomService, batiment)

dateEmbauche

Embauche

Page 41: 3-Real10-11 (1)

La réalisation Annie Culet 41

Passage du diagramme de classes au relationnel

� R3 : une association dont l’un des rôles est de multiplicité 0..1 devient une relation dont :

les attributs sont les clés des relations représentant les classes associées et les attributs de la classe association,

la clé est la clé de la relation RC représentant la classe C associée au rôle inverse ,

les clés des relations représentant les classes associées sont clés étrangères.

réfOuvrage {unique}titreOuvragegenreOuvrage

Ouvrage

numAdhérent {unique}nomAdhérentadresseAdhérent

Adhérent0..4

0..1emprunt

emprunteur

dateEmprunt

Emprunt

OUVRAGE(réfOuvrage, titreOuvrage, genreOuvrage)ADHERENT(numAdhérent, nomAdhérent,adresseAdhérent)EMPRUNT(#réfOuvrage, #numAdhérent, dateEmprunt)

Page 42: 3-Real10-11 (1)

La réalisation Annie Culet 42

Passage du diagramme de classes au relationnel

� R4 : une association dont les rôles sont de multiplicité * devient une relation dont :

les attributs sont les clés des relations représentant les classes associées et les attributs de la classe association,

la clé est formée par les clés des relations représentant les classes associées, qui sont aussi clés étrangères.

nom {unique}spécialité

Enseignant

intitulé {unique}matièrenbHeures

Cours

coursDonné

1..*enseignant

1..*

ENSEIGNANT(nom, spécialité)COURS(intitulé, matière,nbHeures)ENSEIGNE(#nom, #intitulé, numSalle)

numSalle

Salle

Page 43: 3-Real10-11 (1)

La réalisation Annie Culet 43

Passage du diagramme de classes au relationnel

� Que devient un attribut calculé d’une classe ?

� en général non représenté : il sera calculé dynamiquement (par une procédure au

niveau application).

� on peut néanmoins décider (pour des raisons de performance) de représenter

l'attribut dérivé mais il sera nécessaire dans ce cas d’assurer que la valeur stockée

évolue en même temps que les attributs sur lesquels le calcul dérivé porte.

� Compléter votre schéma en notant les attributs obligatoires avec *

� Exprimer toutes les contraintes d’intégrité en français

Page 44: 3-Real10-11 (1)

La réalisation Annie Culet 44

… le schéma relationnel

OUVRAGE (réfOuvrage, titreOuvrage*, genreOuvrage*, dateParution*, #(nomAuteur, prenomAuteur)*)

AUTEUR (nomAuteur, prenomAuteur, nationalité*)

ADHERENT (numAdhérent, nomAdhérent*, adresseAdhérent*, categorie*)

EMPRUNT (#réfOuvrage, #numAdhérent*, dateEmprunt*)

contrainte d’intégrité :

Dans EMPRUNT: un adhérent a au plus 4 ouvrages empruntés.

Gestion d’une bibliothèque

Page 45: 3-Real10-11 (1)

La réalisation Annie Culet 45

Mapping vers le relationnel depuis Ada

� Motivation

avoir un niveau d'accès aux données qui masque la couche SGBD relationnel qui réalise la persistance

=>permet de développer une couche application sans SQL

� Une variable structurée permet de représenter directement un n-uplet (une entité) stocké dans une table du SGBD

Le type structuré a des attributs qui correspondront aux champs (colonnes) de la table qu'elle représente

On définit un type structuré pour chaque table de la BD

Page 46: 3-Real10-11 (1)

La réalisation Annie Culet 46

Mapping vers le relationnel depuis Ada

Andrea

Andrea

prenomAuteur

Camilleri

Camilleri

nomAuteur

février 2006romanla prise de MalakéCAM128

janvier 2008policierla lune de papierCAM645

dateParutiongenreOuvragetitreOuvragerefOuvrage

� On définit un type structuré pour représenter un enregistrement de cette table :

type tOuvrage is recordrefOuvrage : String; titreOuvrage : String; genreOuvrage : tgenre_enum;dateParution: Date;nomAuteur : String;prenomAuteur : String;

end record;

� On définit également des procédures/fonctions pour manipuler les variables de ce type.

Exemple : table Ouvrage contenant des ouvrages :

Page 47: 3-Real10-11 (1)

La réalisation Annie Culet 47

Besoin d’un outil

� Implémenter "à la main" un mapping est une tâche répétitive, fastidieuse et délicate (en particulier adéquation entre les types de données SQL et ceux de Ada)

� Il existe des outils dans d’autres langages pour réaliser cette corvée de façon "propre" et automatique :

en java : Torque, ...

en PHP : Propel,...

� En Ada, un outil a été développé selon les mêmes principes : Mill

http://www.virtual-worlds.biz/downloads/mill/

Page 48: 3-Real10-11 (1)

La réalisation Annie Culet 48

Principe de Mill (de Torque, …)

Fichier décrivant le

schéma relationnel

de la BD

(format XML)

Un type structuré par table

Un ensemble de procédures par table

GénérateurMill

Page 49: 3-Real10-11 (1)

La réalisation Annie Culet 49

Schéma XML correspondant au schéma relationnel de la BD

<database name= "Biblio" >

<table name= "Ouvrage" >

<column name= "refOuvrage" primaryKey="true" type="CHAR" size=" 6"/>

<column name= "titreOuvrage" required="true" type="CHAR" size=" 80"/>

<column name="genreOuvrage" required="true" type="ENUM"

values = "roman policier SF documentaire théâtre poésie BD" />

<column name="dateParution" required="true" type=" DATE" />

<column name= "nomAuteur" required="true" type="CHAR" size=" 30"/>

<column name= "prenomAuteur" required="true" type="CHAR" size=" 30"/>

<foreign-key foreignTable="Auteur" >

<reference foreign="nomAuteur" local= "nomAuteur "/>

</foreign-key>

<foreign-key foreignTable="Auteur" >

<reference foreign="prenomAuteur" local= "prenomAuteur"/>

</foreign-key>

</table>

Page 50: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 50

Codage du logiciel

� Codage des modules de la couche application du noyau fonctionnel

� Génération de la couche utilitaire avec Mill

� Utilisation des modules fournis par la couche utilitaire

� Propagation des exceptions levées dans la couche application vers la couche IHM

� Codage des tests fonctionnels unitaires

� Écrire les "test_case" avec AUnit et les exécuter

Page 51: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 51

Architecture en couches du NF

ConsulterOuvrage(…)ConsulterAuteur(…)ModifierAdhérent(…)Exception

p_application

couche Application

couche Utilitaire ouvrage_io auteur_io emprunt_io

couche Noyau

Types des donnéesde l’application

biblio_data

gnade/postgres

modules réalisant le mapping vers le relationnel

modules réalisant les CU de l’application et les primitives sur la base

save ()retrieve () …

save ()retrieve () …

save ()retrieve () …

Page 52: 3-Real10-11 (1)

La réalisation Annie Culet 52

Utilisation de Mill

� Pour une BD biblio contenant les tables XXX, Mill génère :

� un module biblio.sql qui permet de créer les relations de la base (CREATE TABLE ouvrage …)

� un module biblio_data dans lequel sont déclarés pour chaque table XXX :

le type structuré XXX correspondant ( type touvrage is record ….)

un module XXX_list qui gère un ensemble d’éléments de ce type ( package ouvrage_list …)

� un module base_types qui contient en particulier les déclarations des types énumérésutilisés s’il y en a (type tgenre_enum, …)

� pour chaque table XXX un module XXX_io qui contient les procédures permettant de réaliser les mises à jour dans la table (ouvrage_io, …)

Retrieve_By_PK, Retrieve, Save, Delete

Add_nomAtt pour valoriser une clause WHERE (add_titreOuvrage, …)

Page 53: 3-Real10-11 (1)

La réalisation Annie Culet 53

Création simple

� Pour créer un nuplet dans une table, il suffit de donner des valeurs aux attributs de la variable structurée correspondante et de la sauvegarder dans la BD par la procédure save.

� Mill traduira cela par une requête SQL « insert ».

ouvrage_item : biblio_data.touvrage;

ouvrage_item.refOuvrage := "CAM645" ;

ouvrage_item.titreOuvrage := "la lune de papier" ;

….

ouvrage_io.save (ouvrage_item, false);

une exception est levée si l’ouvrage existe déjà.

Page 54: 3-Real10-11 (1)

La réalisation Annie Culet 54

Rechercher un nuplet dans la base� Pour rechercher à partir de la clé primaire, il suffit de passer la valeur de la clé à la

procédure retrieve_by_pk.

� Mill va exécuter une requête " select "

ouvrage_item : biblio_data.touvrage; ref : Unbounded_String;

ref := "CAM645" ;ouvrage_item := ouvrage_io.retrieve_by_pk (ref);

retourne biblio_data.null_ouvrage s’il n’est pas trouvé

à tester avec la fonction Is_Null

Page 55: 3-Real10-11 (1)

La réalisation Annie Culet 55

Rechercher un ensemble de nuplets dans la base

� Pour rechercher à partir de la valeur d’un ou plusieurs attributs, on affecte les attributs et on utilise la procédure retrieve.

� Mill va exécuter une requête " select " avec une clause WHERE

Vector est une collection d’éléments (voir les containers en Ada)ouvrage_list_item: biblio_data.ouvrage_list.vector; criteria : db_commons.criteria;

rechercher tous les ouvrages

ouvrage_list_item := retrieve(criteria)

rechercher tous les ouvrages du genre policier

ouvrage_io.add_genreOuvrage (criteria, policier);ouvrage_list_item := retrieve(criteria);

retourne biblio_data.null_ouvrage_list si le résultat est vide

à tester avec la fonction Is_Empty

Page 56: 3-Real10-11 (1)

La réalisation Annie Culet 56

Modification, suppression� Pour modifier un nuplet

idem création mais ….ouvrage_io.save (ouvrage_item, true);

� Pour supprimer un nupletidem rechercher mais ….ouvrage_io.delete (criteria)

Page 57: 3-Real10-11 (1)

La réalisation Annie Culet 57

Equivalence des types Ada/SQL

values

size, scale

size

Attributs

type énuméré

type décimal contraint

boolean

long_float

integer

unbounded_string

ada.calendar.time

Type ada

ENUM

DECIMAL

BOOLEAN

REAL

INTEGER

CHAR

DATE|DATETIME|TIME

Type Fichier XML

Page 58: 3-Real10-11 (1)

La réalisation Annie Culet 58

ODBC, GNADE� ODBC (Microsoft) (comme JDBC Sun Java) :

API Interface de Programmation (Application Programming Interface) permet la connexion, interrogation et sa mise à jour de la base de données, traitement des erreursindépendante de tout SGBD particulier nécessite un driver (pilote) spécifique au SGBD utilisé

� GNADE (GNU Ada Database Environment) : interface SQL avec Ada 95 suivant le principe de l'Embedded SQL (SQL embarqué).

Utilise l’API ODBC disponible sur Linux, Solaris et Windows/NT

Page 59: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 59

Traitement des exceptions

….créerOuvrage(…)Exceptionwhen

ExOuvrageExistant => …

ExOuvrageExistantcréerOuvrage(…)

ExOuvrageAjouterajouter (…)

ExFiEcrireecrire(…)

interfacecorps

coucheApplication

coucheUtilitaire

coucheFichier

couche IHM Module

Toutes les exceptions sont propagées jusqu’au niveau IHM pour y être traitées dans leur contexte.

noyau fonctionnel

Propagation exception

Page 60: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 60

Exception - Rappel1. traitée localement

Procedure Q(…)begin… ;P(…);… ;

end Q;

Procedure P(…)begin… ;�_____… ;Exceptionwhen Ex => … ;

end P;

TE

si Ex est levée, elle est traitée par le Traite-Exception TE qui achève l’exécution de P. Q ne sait pas que son appel à P s’est "mal terminé".

l’exception Ex est levéeabandon de la suite d’instructions

contrôle transféré au Traite-Exception TE

Page 61: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 61

Exception - Rappel 2. propagée à l’unité appelante

Procedure Q(…)begin… ;P(…);�_____… ;

Exceptionwhen Ex => … ;

end Q;

Procedure P(…)begin… ;�_____… ;end P;

TE

la même exception Ex (ou ExAlias si renommage) est levée (propagation) et traitée par le Traite-Exception TE qui achève l’exécution de Q

l’exception Ex est levéeabandon de la suite d’instructions

La propagation continue tant que l’unité qui la reçoit n’a pas de Traite-Exception.Si la propagation arrive au programme principal, l’exécution du programme s’arrête.

l’exception peut être propagée sous un autre nomExAlias : exception renames Ex

pas de Traite-Exception dans P � propagation dans l’unité appelante

Page 62: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 62

Exception - Rappel 3. redéclenchement d’une exception

Procedure Q(…)begin… ;P(…);�_____… ;

end Q ;

Procedure P(…)begin… ;�_____… ;Exceptionwhen Ex => … ;

raise Ex2;end P ;

TE

l’exception Ex2 est levée

l’exception Ex est levéecontrôle transféré au Traite-Exception TE

redéclenche l’exception Ex2 pour l’unité appelante

Ex2 est traitée par un Traite-Exceptionou propagée à l’unité appelante

Redéclencher une autre exception est une forme de propagation de l’exception initiale.

Page 63: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 63

Renommaged’une exception, d’une procédure

�Utilisation des ressources d’un module :

pour établir la visibilité de son interface : clause with

�Identification d’une ressource (procédure, fonction, exception, …)

� par le nom complet (notation pointée) : préfixage par le nom du module

P_ ensembleOuvrage.ExEnsConsulter

� visibilité directe : utilisation de la clause use mais problème de conflit de noms

ExEnsConsulter de p_ensembleOuvrage ou de p_ensembleAuteur ?

� renommage (désignation sous un nouveau nom) : utilisation du renames

ExOuvrageConsulter : exception renames p_ensembleOuvrage.ExEnsConsulter;

les exceptions de la couche application sont souvent redéclenchées pour être propagées sous le nom énoncé dans la conception de l’interface de cette couche.

Page 64: 3-Real10-11 (1)

Réalisation Logiciel Annie Culet 64

Exemple de propagation d’exceptionsProcedure consulterOuvrage (oIdf : in touvrageIdf ; oVal : out tOuvrageVal ; aVal : out tauteurVal);

…ensembleOuvrage.consulter (oIdf, oVal);-- cas ouvrage non empruntéif oVal.emprunt = empruntNul

then raise ExOuvrageDisponible;end if;ensembleAuteur.consulter (oVal.auteur, aVal);

exceptionwhen ExOuvrageConsulter => raise ExOuvrageNonTrouvewhen ExOuvrageFatal | ExAuteurFatal => raise ExOpFatal;

end consulterOuvrage;

Procedure on_button_rechercher_clicked (…) is…consulterOuvrage (oIdf , oVal , aVal );consulterEmprunt (oVal.emprunt , eVal);…exception when ExOuvrageNonTrouve => rep := Message_Dialog (« Référence de l’ouvrage incorrecte»);when ExopFatal => rep := Message_Dialog (« Problème sur la base »);when ExOuvrageDisponible => …when ExConversion => return; couche IHM

couche Application

Page 65: 3-Real10-11 (1)

Réalisation IHM Annie Culet 65

Utilitaire pour le composant Tree_View

with Gtk.Tree_View; use Gtk.Tree_View;

with Gtk.Tree_Store; use Gtk.Tree_Store;

with Glib; use Glib;

-- prévu uniquement pour afficher des chaînes

package p_util_treeview is

-- création d'une colonne dans une tree_view avec un titre. Le titre peut être visible ou non.

procedure creerColonne (titre : UTF8_String ; treeview : Gtk_Tree_View; titreVisible : boolean);

-- création d'un modèle pour une tree_view. Il contient les données destinées à alimenter la vue.

procedure creerModele ( treeview : Gtk_Tree_View; modele : out Gtk_Tree_Store);

end p_util_treeview;

Page 66: 3-Real10-11 (1)

Réalisation IHM Annie Culet 66

Affichage dans un composant Tree_View

Interface couche ApplicationconsulterAuteur(autIdf :in tAuteurIdf ; listeOuvVal :out tlisteOuvrageVal);

Exception : ExAuteurNonTrouvé

type tAuteurVal is recordnomAuteur : tnomAuteur ;prénomAuteur : tprénomAuteur ;nationalitéAuteur : tnationalitéAuteur ;publication : tEnsOuvrageIdf;

end record;

Procedure on_buttonRechercher_clicked (…) is

1. -- récupération de la valeur saisie et conversion au type Ada du modèle de données

-- le bouton Fermer de la région 2 ne doit pas être activable

2. -- appel de la procédure du noyau fonctionnel.

consulterAuteur (autIdf, listeOuvVal ) ;

3. -- les boutons Rechercher/Annuler de la région 1 ne doivent pas être activables, …

-- préparation de la tree_view pour afficher la liste des ouvrages

creerColonne ("référence" , treeViewOuvrage, false); -- 3 fois pour les 3 colonnes sans titrecreerModele (treeViewOuvrage, modeleOuvrage) ; -- associe le modèle à la vue

-- modeleOuvrage : Gtk_Tree_Store; utilise le module Gtk.Tree_Store

Spécification{ } �{la liste des ouvrages de l’auteur sélectionné est affichée dans la fenêtre}

Page 67: 3-Real10-11 (1)

Réalisation IHM Annie Culet 67

Affichage dans un composant Tree_View

4. -– affichage des valeurs résultat dans la région 2 de la fenêtre dans un composant tree_view

-- la liste chaînée est parcourue avec le module p_list

listeCourante := listeOuvVal;while not estVide (listeCourante) loop

ouvVal := premier (listeCourante);-- ajout d’une ligne dans le modèle

append (modeleOuvrage, rangOuvrage, null_iter); -- rang désigne une ligne-- alimente les 3 colonnes de la ligne avec une valeur de type chaîne

set(modeleOuvrage, rangOuvrage, 0, ouvVal.refOuvrage); --colonne 1set(modeleOuvrage, rangOuvrage, 1, ouvVal.titreOuvrage); -- colonne 2set(modeleOuvrage, rangOuvrage, 2, p_conversionGenre.to_string(ouvVal.genreOuvrage));listeCourante := suite(listeCourante);

end loop;

-- une fois le modèle alimenté, la vue s’affiche automatiquement

-- rangOuvrage : Gtk_Tree_Iter := Null_Iter; utilise le module Gtk.Tree_Model;

-- le module p_conversionGenre instancie le module générique p_enum du module p_conversion pour le type tgenreOuvrage;

Page 68: 3-Real10-11 (1)

Réalisation IHM Annie Culet 68

Sélection dans un composant Tree_View

-- des valeurs sont affichées dans une ou plusieurs colonnes d’une Tree_View

-- récupération de la ligne sélectionnée (rang)

Get_Selected (Get_Selection (treeviewOuvrage), Gtk_Tree_Model(modeleOuvrage), rangOuvrage);

-- récupération de la valeur de la colonne 1 dans la ligne (une chaîne)

-- et conversion au type Ada

to_ada_type (Get_String (modeleOuvrage, rangOuvrage, 0), ouvVal.refOuvrage);

-- utlise le module Gtk.Tree_Selection

… on veut récupérer la référence de l’ouvrage dans la ligne sélectionnée de la tree_view précédente.

Page 69: 3-Real10-11 (1)

La réalisation Annie Culet 69

Test de logiciel

Pourquoi ?

Réutilisation dans Ariane 5 d’un composant logiciel d’Ariane 4.

... une seule petite variable : l'accélération horizontale.

l'accélération maximum d'Ariane 4 était d'environ 64

l'accélération maximum d'Ariane 5 était d'environ 300

la variable codée sur 8 bits a connu un dépassement de capacité …

KOUROU, Guyane 4 Juin 1996

37 secondes après le décollage

la fusée Ariane 5 explose en

plein ciel à 4000 m d'altitude.

Page 70: 3-Real10-11 (1)

La réalisation Annie Culet 70

Définition du test� Ce que n’est pas le test :

un moyen de s’assurer qu’un logiciel fonctionne.

� Ce qu’est le test :

� un processus - manuel ou automatique- dont le but est de mettre en évidence les

défauts d’un logiciel.

Défaut,anomalie : manifestation d’une erreur lors de

l’exécution

Erreur : écart entre une valeur (ou condition) observée ou

mesurée et la valeur (ou condition) spécifiée ou th éoriquement

correcte

� une activité destructrice : un bon test est un essai qui trouve des erreurs. � une activité centrale dans le processus de développement

Page 71: 3-Real10-11 (1)

La réalisation Annie Culet 71

Test et qualité du logiciel� Le test, une activité non valorisante ?

� La majorité des logiciels ne sont pas suffisamment testés.

� Le test n’est pas du debugging:

� le test ne doit pas être fait par les développeurs (sauf tests unitaires)

� son objectif n’est pas de localiser les erreurs, ni de les corriger

� L’objectif du test n’est pas de montrer que le logiciel ne comporte plus d’erreurs

� il restera toujours des erreurs !

� le test est un moyen d’atteindre un niveau de qualité du logiciel. Celui-ci dépend du

contexte d ’utilisation du logiciel.

� Le test exhaustif d’un logiciel est impossible.

Page 72: 3-Real10-11 (1)

La réalisation Annie Culet 72

Coût du test

Une grande partie des activités de test est effectuée en fin de développement et plus une faute est détectée tard, plus elle coûte cher… dans un contexte où les testeurs accumulent

tous les retards pris par les phases précédentes.

L’activité de test

composante à part entière dans le cycle de développement d’un logiciel

AnalyseConception40%

Codage20%

TestInstallation

40%

En moyenne, on trouve entre 100 et 150 erreurs pour chaque millier de lignes de code écrites à la main.

Page 73: 3-Real10-11 (1)

La réalisation Annie Culet 73

Niveaux de test et cycle de vie

Codage

Tests unitaires

Tests d’intégration

Tests de validation

Tests de recette

Plans de tests Résultats des tests

Conception détaillée

Conception globale

Spécification

Expression des besoins

Page 74: 3-Real10-11 (1)

La réalisation Annie Culet 74

Niveaux de test� Test unitaire

test d’un composant du logiciel pris isolément (par ex. une procédure, un module, ...)

� Test d’intégration

succession de tests dans laquelle les composants sont progressivement assemblés en

suivant la relation d’utilisation. Vérification des spécifications fonctionnelles et

techniques. Test des interfaces entre composants.

� Test de validation

vérification de la conformité du produit final aux spécifications.

� Test de recette

test dans les locaux de l’acquéreur pour vérifier que les dispositions contractuelles

sont bien vérifiées.

Page 75: 3-Real10-11 (1)

La réalisation Annie Culet 75

Test de non régression

� Problématique : "Je ne comprends pas. Hier ça marchait …" Il est très souvent impossible de répondre.

La non régression du code (une nouvelle version du code est au moins aussi bonne que

la précédente) est la certitude que l’on avance.

� Test de non régression : test effectué suite à une modification afin de montrer que

l’ensemble n’a pas été affecté (ex. par un effet de bord non prévu).

� Comment ? : tester la nouvelle version du composant ou d’un ensemble de

composants avec le jeu de test précédent.

� Quand? : tests unitaires, test d’intégration

Page 76: 3-Real10-11 (1)

La réalisation Annie Culet 76

Tests statiques / dynamiques

� Statiques

inspection : examen du code sans exécution par des personnes n’ayant pas participé

au codage

� méthode efficace et peu coûteuse

� nécessaire mais pas suffisante

� ne permet pas de valider le comportement du logiciel

� risque de provoquer des tensions

� Dynamiques

exécution du programme avec un jeu de test

Ces 2 méthodes sont complémentaires

Page 77: 3-Real10-11 (1)

La réalisation Annie Culet 77

Test dynamique : familles� Test fonctionnel (test de boite noire)

à partir des spécifications (informelles, semi-formelles, formelles). L’implémentation

des composants n’est pas connue (le code n’est pas utilisé pour sélectionner les

données de test).

objectif : mettre en évidence un écart entre le comportement réel et le comportement spécifié d’un programme ou d’un composant.

� Test structurel (test de boite blanche)

à partir de la structure interne du programme.

C’est l’implémentation qui est testée.

objectif : couvrir tous les ‘chemins’ possibles dans le code afin mettre en évidence des erreurs dans l’exécution du programme.

� Test de performance

évaluation des performances d'un système par simulation des conditions réelles d'utilisation

� Test IHM (interface homme-machine)

test du comportement de l’interface (menu, fenêtre, navigation ...)

Page 78: 3-Real10-11 (1)

La réalisation Annie Culet 78

Test dynamique : étapes� Formulation d’une stratégie de test

� niveaux de test à appliquer et leurs objectifs

� méthodes, techniques, outils

� Définition des plans de test

� quels composants, dans quel ordre ?

� comment appliquer la stratégie ? (tests des versions successives, critères d’arrêt des

tests, …)

� Description de fiches de test (valeurs à l’entrée du test, sorties attendues)

� Exécution des fiches de test spécifiées

� Observation des résultats

Page 79: 3-Real10-11 (1)

La réalisation Annie Culet 79

Les difficultés du test� Comment déterminer les jeux de test pertinents ?

� sélection des tests assurant un bon échantillonnage des cas possibles (entrées

valides, invalides, inattendues, aux limites) : couverture du domaine des entrées.

� Comment déterminer les oracles des tests ?

� décider si le test est un échec ou un succès (rôle de l ’oracle)

� comparaison des résultats observés avec ceux attendus

� (les résultats - valeurs, propriétés- ne sont pas forcément facilement accessibles …)

� Comment décider de l’arrêt des tests ?

� impossible de tester un système de façon exhaustive

� nécessité de définir des critères d’arrêt

Page 80: 3-Real10-11 (1)

La réalisation Annie Culet 80

Méthode fonctionnelle (1)

� Tests boite noire : tests conçus à partir de la spécification du programme (la structure

du programme est inconnue) : Pour chaque fonctionnalité requise d’un programme,

sélection d’un jeu de tests

� Objectif : tester tous les comportements du programme afin de détecter les écarts par

rapport au comportement spécifié (fonctions non conformes ou manquantes) . Vérifier les

critères qualité (sécurité, portabilité, …)

Difficulté de mettre en œuvre des méthodes systématiques lorsque les spécifications ne

sont pas écrites dans un langage formel.

Page 81: 3-Real10-11 (1)

La réalisation Annie Culet 81

Méthode fonctionnelle (2)

1. A partir de la spécification, identification des fonctionnalités élémentaires pouvant

être testées séparément.

Exemple : programme réalisant les opérations courantes sur un compte bancaire

Fonctionnalités :

créditer (compte, montant) retourner solde

débiter (compte, montant) retourner solde

consulter (compte) retourner solde

-- solde : solde du compte

-- montant : montant de dépôt ou du retrait

Page 82: 3-Real10-11 (1)

La réalisation Annie Culet 82

2. Pour chaque fonctionnalité, sélectionner un jeu de tests garantissant une bonne

couverture du domaine des entrées :

dans les limites fonctionnelles, hors limites, aux limites.

débiter (compte : COMPTE, montant : réel+ ) retourner solde : réel

contraintes :

solde >= solde-min du compte (découvert maximum autorisé)

montant <= montant-max du compte (retrait maximum autorisé)

conditions préalables : compte ∈∈∈∈ COMPTE ; solde initial >= solde-min

précondition : montant<=montant-max

traitement solde final := solde initial - montant

postcondition : solde final >= solde-min

Méthode fonctionnelle (3)

Page 83: 3-Real10-11 (1)

La réalisation Annie Culet 83

Méthode fonctionnelle (4)Sélection du jeu de test :

Découper le domaine des entrées en classes d’équivalence de façon à ce que chaque

classe corresponde aux valeurs faisant l’objet d’un traitement différent dans la

spécification.

Pour chaque classe : sélectionner un élément

déterminer la valeur des sorties attendues

valeur non valide

valeur non valide

montant

montant-max

x

valeur valide

réel

0

x x

valeur spéciale

x

Domaine du montant du retrait

Page 84: 3-Real10-11 (1)

La réalisation Annie Culet 84

Méthode fonctionnelle (5)Rajouter les valeurs aux bornes des entrées (limites)

x

valeur valide extrême

x

valeur spéciale

montant

montant-max

x x

valeur valide

valeur non valide

réel

0

x

valeur non valide

Solde initial - montant = solde-min

x

opération refusée

solde initial

solde-min

xx

valeur valide

réelxvaleur valide extrême

Domaine du montant du retrait

Domaine du solde

Page 85: 3-Real10-11 (1)

La réalisation Annie Culet 85

Méthode fonctionnelle (6)

Solde init Solde-min montant max-retrait Solde final

500 -300 -200 700 500

500 -300 0 700 500

500 -300 300 700 200

500 -300 700 700 -200

Cas

mont < 0

mont = 0

normal

limite

Résultat attendu

refus

refus

OK

OK

500 -300 900 700 500 non valide refus

-200 -300 400 700 -200

100 -300 400 700 -300

200 -300 400 700 -200

non valide

limite

valide

refus

OK

OK

-300 -300 400 700 -300 non valide refus

Page 86: 3-Real10-11 (1)

La réalisation Annie Culet 86

Méthode fonctionnelle (7)

100

-200

--300300

-200 300 400 900 montant

Solde initial

00

200

Domaine de valeurs valides

500

700700

OK

refus

2 jeux de valeurs pour le même cas

Page 87: 3-Real10-11 (1)

La réalisation Annie Culet 87

Quand écrire les tests unitaires?

� L'une des pratiques les plus en vogue aujourd'hui, l'eXtreme Programming, nous dit de les écrire avant même de commencer à coder.

� Avant d'écrire un composant avec des défauts

� d'abord se demander ce que le composant de programme doit faire et écrire un

programme de test

� puis réaliser le composant et donc constater que celui-ci a des défauts parce que le test unitaire ne passe pas. Mais ….

� Avantages

� réfléchir aux pré et post conditions

� préciser les règles de validité de paramètres

� éviter d’écrire du code inutile

Page 88: 3-Real10-11 (1)

La réalisation Annie Culet 88

AUnit� Aunit : Framework* de tests unitaires et de non régression

� ensemble de modules Ada de la famille xUnit (Junit, Cunit, ...)

� facilite la création et l’exécution de tests pour des applications Ada

� beaucoup plus qu’une alternative aux "println" !

� Principe :

� Tests avec entrées normales, limites, hors limites et comparaison avec résultats

attendus

*Framework : ossature générale d’une application offrant une partie commune de

traitements et que chaque utilisateur personnalise pour son cas particulier.

Page 89: 3-Real10-11 (1)

La réalisation Annie Culet 89

Aunit : la non régression� Cas de test (Test_Case)

module contenant un ensemble de procédures de test

+ Set_Up : procédure exécutée avant l’appel d ’une procédure de test

+ Tear_Down : procédure exécutée après l’exécution d’une procédure de test

� Suite de tests (Test_Suite)

empilement de Test_Case

� Lancement des tests (Test_Run)

lancement d’une suite de tests avec édition d’un rapport de test

Test_Case

Test_Suite

Proc. de test

Proc. de test

Proc. de test

T_C T_C

P

PP

P

P

P

P

Set_Up Tear_Down S_U T_D S_U T_D

Page 90: 3-Real10-11 (1)

La réalisation Annie Culet 90

Test_Case (1)with AUnit.Test_Cases.Registration; use AUnit.Test_C ases.Registration;

with AUnit.Assertions; use AUnit.Assertions;

-- modèle pour un module cas de test

package body p_ XXXX is

-- préparation : exécutée avant chaque procédure de te st

procedure Set_Up (T : in out Test_Case) isbegin-- effectuer toutes les initialisations nécessaires

null;

end Set_Up ;

-- exécutée après chaque procédure de test procedure Tear_Down (T : in out Test_Case) isbegin-- remettre au propre l’environnement pour la procédur e de test suivante

null;

end Tear_Down;

Page 91: 3-Real10-11 (1)

La réalisation Annie Culet 91

Test_Case (2)-- procédure de test. Autant de procédures que néces saires

procedure Test 1 (R : in out AUnit.Test_Cases.Test_Case'Class) isbegin-- le corps de la procédure de test

null;-- teste les résultats attendus-- plusieurs assertions et actions sont possibles

Assert (boolean_Expression, "indication de l’erreur");

end Test 1;

Les assertions :

Aunit.Assertions.Assert(boolean_Expression, descrip tion);

description : chaîne éditée dans le rapport lorsque l’expression booléenne est fausse

Exemple : dans une procédure de test de l’opération addition

x:= 12; y := 14;assert (x + y = 26, "l’addition est incorrecte");

Page 92: 3-Real10-11 (1)

La réalisation Annie Culet 92

Test_Case (3)

-- Enregistrement des procédures de test

procedure Register_Tests (T : in out Test_Case) is

begin-- à répéter pour chaque procédure de test

Register_Routine (T, Test 1'Access ,"nommage de la procédure de test");

end Register_Tests;

-- Identification du cas de test

function Name (T : Test_Case) return String_Access is

beginreturn new String' ("nom du cas de test");

end Name;

end p_ XXXX;

Page 93: 3-Real10-11 (1)

La réalisation Annie Culet 93

Suite de testswith AUnit.Test_Suites; use AUnit.Test_Suites;

-- Liste des cas de test à empiler

with p_ XXXX;

with p_ YYYY;

function Une_Test_Suite return Access_Test_Suite is

Result : Access_Test_Suite := new Test_Suite;

begin

-- ajout des cas de test

Add_Test (Result, new p_ XXXX.Test_Case);

Add_Test (Result, new p_ YYYY.Test_Case);

return Result;

end Une_Test_Suite ;

Page 94: 3-Real10-11 (1)

La réalisation Annie Culet 94

Lancement d’une suite de tests

with AUnit.Test_Runner;

-- Suite de tests

with Une_Test_Suite;

procedure Test_Run is

procedure Run is new AUnit.Test_Runner ( Une_Test_Suite );

begin

Run (Timed => False);

end Test_Run ;

Note : Il est possible d ’empiler plusieurs suites de tests.

Cette possibilité n ’est pas illustrée dans ce cours.

Page 95: 3-Real10-11 (1)

La réalisation Annie Culet 95

ExempleOpération de débit sur un compte bancaire-1

Les contraintes : si ces conditions ne sont pas satisfaites, le compte n’est pas débité.

le découvert maximum autorisé sur le compte est de 300 €

le retrait maximum autorisé est de 700 €.

subtype tcompteNumero is string (1 .. 10) ;subtype tsolde is float ;subtype tretrait is float range 0.0 .. float’last ;

type tcompte is recordnumero : tcompteNumero ;solde : tsolde ;

end ;procedure debiter(compte:in out tcompte; montant:in tretrait);

-- condition préalable à l’opération : compte.solde >= -300-- précondition de l’opération : montant <= 700-- postcondition de l’opération : compte.solde >= -300

ExRetraitImpossible:exception ; -- levée dans tous les cas où le retrait est refusé ; l e solde reste identique.

procedure initialiserCompte (compte:in out tcompte; m ontant:in tsolde);

-- initialise le solde du compte avec montant (>=-30 0)

Page 96: 3-Real10-11 (1)

La réalisation Annie Culet 96

ExempleOpération de débit sur un compte bancaire-2

package body p_TestDebitSoldeInitConstant is

leCompte : tcompte;

procedure Set_Up (T : in out Test_Case) isbegin

initialiserCompte (leCompte, 500);end Set_Up;

procedure Tear_Down (Test : in out Test_Case) isbegin

null;end Tear_Down;

function Name (T : Test_Case) return String_Access isbegin

return new String'(" Test de l’opération de débit en faisant varier le retrait ");

end Name;

Page 97: 3-Real10-11 (1)

La réalisation Annie Culet 97

ExempleOpération de débit sur un compte bancaire-3

-- cas normal. Retrait possibleprocedure test _debitOk1 (T : in out AUnit.Test_Cases.Test_Case'Class) is

begindebiter (leCompte, 300) ;assert (leCompte.solde=200, “débit non correctement effectué”) ;

exception when ExRetraitImpossible => assert (false, “le retrait devrait être effectué”) ;

end test_ debitOk1;

-- cas où le montant du retrait dépasse le maximum a utoriséprocédure test_ debitRefus1 (t : in out Aunit.Test_Cases.Test_Case’Class) is

begindebiter (leCompte, 900) ;assert (false, “montant retrait trop important non t raité”) ;

exception when ExRetraitImpossible => assert (leCompte.solde=500 ,“le solde devrait rester identique”);

end test_ debitRefus1 ;

Page 98: 3-Real10-11 (1)

La réalisation Annie Culet 98

-- cas où le montant du retrait est égal au maximum autorisé

procédure test_ debitLimite1 (t : in out Aunit.Test_Cases.Test_Case’Class) is

begindebiter (leCompte, 700) ;assert (leCompte.solde = -200, “débit non correctemen t effectué”) ;

exception when ExRetraitImpossible => assert (false, “le retrait devrait être effectué”) ;

end test_ debitLimite1 ;

procedure Register_Tests (T : in out Test_Case) is

beginRegister_Routine(T,Test_ DebitOk1 'Access, " Test retrait cas normal ");Register_Routine(T,Test_ DebitRefus1 'Access, " Test retrait trop important ");Register_Routine(T,Test_ DebitLimite1 'Access," Test retrait limite autorisée ");

end Register_Tests;

end p_TestDebitSoldeInitConstant ;

ExempleOpération de débit sur un compte bancaire-4

Page 99: 3-Real10-11 (1)

La réalisation Annie Culet 99

package body p_TestDebitRetraitConstant is

leCompte : tcompte; retrait : tretrait ;

procedure Set_Up (T : in out Test_Case) isbegin

retrait := 400;end Set_Up;

procedure Tear_Down (Test : in out Test_Case) isbegin

null;end Tear_Down;

function Name (T : Test_Case) return String_Access isbegin

return new String'(" Test de l’opération de débit en faisant varier le solde initial ");

end Name;

ExempleOpération de débit sur un compte bancaire-5

Page 100: 3-Real10-11 (1)

La réalisation Annie Culet 100

-- cas où le montant du découvert autorisé est dépas sé

procédure test_ debitRefus2 (t : in out Aunit.Test_Cases.Test_Case’Class) is

begininitialiserCompte (leCompte, -200);debiter (leCompte, retrait) ;assert (false, “ cas découvert non autorisé non trait é ”) ;

exception when ExRetraitImpossible => assert (leCompte.solde = -2 00, “ le solde devrait rester identique ”) ;

end test_ debitRefus2 ;

-- cas où le montant du découvert autorisé est attei nt

procédure test_ debitLimite2 (t : in out Aunit.Test_Cases.Test_Case’Class) is

begininitialiserCompte (leCompte, 100);debiter (leCompte, retrait) ;assert (leCompte.solde = -300, “débit non correctemen t effectué”) ;

exception when ExRetraitImpossible => assert (false, “le retrait devrait être effectué”) ;

end test_ debitLimite2;

ExempleOpération de débit sur un compte bancaire-6

Page 101: 3-Real10-11 (1)

La réalisation Annie Culet 101

ExempleOpération de débit sur un compte bancaire-7

-- cas normal : le montant du découvert n’est pas dé passé

procédure test_ debitOk2 (t : in out Aunit.Test_Cases.Test_Case’Class) is

begininitialiserCompte (leCompte, 200);debiter (leCompte, retrait) ;assert (leCompte.solde = -200, “débit non correctemen t effectué”) ;

exception when ExRetraitImpossible => assert (false, “le retrait devrait être effectué”) ;

end test_ debitOk2 ;

procedure Register_Tests (T : in out Test_Case) is

beginRegister_Routine(T,Test_ DebitOk2 'Access, " Test cas normal ");Register_Routine(T,Test_ DebitRefus2 'Access, " Test découvert non autorisé ");Register_Routine(T,Test_ DebitLimite2 'Access," Test découvert limite ");

end Register_Tests;

end p_TestDebitRetraitConstant ;

Page 102: 3-Real10-11 (1)

La réalisation Annie Culet 102

Méthodes structurelles (1)

� tests boite blanche : tests conçus à partir de la structure du code (flot de contrôle, flot

de données):

Objectif : détecter les fautes d’implémentation

� Couverture du flot de contrôle

toutes les instructions, conditions, chemins exécutables, …

� Couverture du flot de données

toutes les définitions de variables, leurs utilisations, …

Page 103: 3-Real10-11 (1)

La réalisation Annie Culet 103

Méthodes structurelles (2)� But : produire des données de test qui exécuteront un ensemble de comportement du

programmeUn programme => un graphe de contrôle

beginif (x<=0) then x:= -xelse x:= 1-x;if (x=-1) then x:=1else x:=x+1;end

a

b c

d

f e

g

x<=0 x>0

x:= -x x:= 1-x

x=-1 x!=-1

x:=1 x:=x+1

Graphe orienté :un noeud : un bloc d’instructionsun arc : la possibilité de transfert de l’exécution d’un noeud à un autre

Une exécution possible = un chemin dans le graphe de contrôleacdeg est un chemin de contrôlebdfg n’est pas un chemin de contrôle

Page 104: 3-Real10-11 (1)

La réalisation Annie Culet 104

Méthodes structurelles (3)L’ensemble des chemins de contrôle du graphe =

abdfg + abdeg + acdfg + acdeg

a

b c

d

f e

g

x<=0 x>0

x:= -x x:= 1-x

x=-1 x!=-1

x:=1 x:=x+1Construction de l’expression des chemins :

séquentielle alternative itérative

a

b

a

b c

d

a

b

c

ab abd + acd a(ba)*c

Page 105: 3-Real10-11 (1)

La réalisation Annie Culet 105

Méthodes structurelles (4)Chemin exécutable – non exécutable

Donnée de test (DT1) : { x=2 }

� DT1 sensibilise le chemin acdfg : acdfg est un chemin exécutable

� abdfg est un chemin non exécutable : aucune DT capable de sensibiliser ce chemin

� sensibiliser un chemin : problème difficileintérêt des outils automatiques (mais attention problème de trouver des DT qui sensibilisent un chemin est non décidable)

Existence de chemins non exécutables :souvent signe de mauvais codage

a

b c

d

f e

g

x<=0 x>0

x:= -x x:= 1-x

x=-1 x!=-1

x:=1 x:=x+1

Page 106: 3-Real10-11 (1)

La réalisation Annie Culet 106

Méthodes structurelles (5)Hiérarchie des techniques de tests structurels

� Couverture de tous les noeuds

sensibiliser tous les chemins de contrôle qui nous permettent de visiter tous les nœuds du graphe de contrôle.

� Couverture de tous les arcs

sensibiliser tous les chemins de contrôle qui nous permettent de visiter tous les arcs du graphe de contrôle.

« tous les arcs» est plus fiable (plus fort) que «tous les nœuds»

� Couverture de tous les chemins

critère le plus fort : impossible à appliquer dès que le code contient un boucle (+ problème des chemins non exécutables)

Page 107: 3-Real10-11 (1)

La réalisation Annie Culet 107

Méthodes structurelles (6)

Le critère de sélection du jeu de tests repose sur le code du programme

� Limitations :

un jeu de tests de taille raisonnable couvrant tous les chemins exécutables est

utopique

les oublis par rapport à la spécification ne sont pas détectés

lors d’une modification du programme, difficile de réutiliser les tests précédents

(problème de non-régression)

� Intérêt :

quantifiable, automatisable

nombreux outils disponibles (Logiscope Verilog, Attol, ...)