• Aucun résultat trouvé

gages, les éléments décrivant les états peuvent être représentés comme des ensembles, des relations, des séquences d’évènements ou des fonctions. Les opérations sont décrites par des prédicats donnés en termes de pré- et post-conditions.

Langages algébriques Les langages de spécification algébriques permettent de définir

les types et structures de données de façon abstraite, de façon similaire à la définition des structures mathématiques de l’algèbre [69], ainsi que les opérations mathématiques sur ces sur ces types de données. Les données ou types de données représentent les fonctionnalités que l’on cherche à implémenter avec un logiciel par un ensemble d’équations ou d’axiomes. Un exemple de langage de spécification algébrique est le Common Algebraic Specification Language (CASL) [70], implémenté dans l’outil FERUS [71] qui permet le développement, le prototypage et l’exécution de spécifications décrites en CASL.

Langages déclaratifs Le concept de programmation déclarative réunit toutes les

mé-thodes de description du comportement fonctionnel d’un système plutôt que de son design, c’est-à-dire sa réalisation selon une structure de contrôle (comme les états du système et les transitions entre ces états) [72]. Les exigences sont décrites comme des relations entre les variables en termes de fonctionnalités ou de règles d’inférence, et l’exé-cuteur du langage (compilateur ou interpréteur) applique sur ces relations un algorithme fixe permettant de renvoyer un résultat. Décrire un ensemble d’exigences HLR dans ce paradigme se distingue d’une solution logicielle dans le fait que le résultat n’est pas produit dans les conditions de la cible. Des exemples de langages déclaratifs sont les langages lo-giques comme le Prolog [73], les langages fonctionnels comme le Haskell [74] ou le Wolfram Language [75], les contraintes [76], ou encore les langages de flux de données comme le Lustre [77].

Pour écrire une description des fonctionnalités du système complète, précise et perfor-mante, le langage de spécification choisi doit pouvoir tirer parti des caractéristiques de la méthode choisie. Nous nous intéressons entre autres à la programmation par contraintes, qui permet notamment de manipuler des données numériques et qui offre une représenta-tion adéquate des exigences combinatoires, ainsi qu’aux flux de données, qui permettent de maîtriser l’évolution du système au cours du temps. Certaines approches s’intéressent à la combinaison de ces méthodes pour tirer parti de leurs différentes caractéristiques [78].

3.2 Méthodologie de la génération de tests

Lors de la génération de tests selon une certaine stratégie pour la validation et la vérifi-cation d’un système1, il faut se poser deux questions fondamentales : “Qu’est-ce qu’on veut

tester ?” et “Quand est-ce qu’on s’arrête de tester ?”. C’est en répondant à ces questions que nous pourrons définir les critères selon lesquels on pourra attester de l’absence d’erreurs dans le logiciel par la génération de tests pertinents. Nous pourrons ainsi valider le compor-tement fonctionnel du système selon un certain niveau de confiance par l’évaluation de la qualité de la campagne de test. Dans cette section, nous détaillerons les activités de test présentées dans le chapitre 1, puis nous présenterons quelques méthodes de résolution de problèmes d’optimisation combinatoires, outils essentiels pour la génération automatique de tests.

3.2.1 Déterminer les points à vérifier à partir d’objectifs de test

Le test exhaustif sur toutes les entrées possible du système étant impossible, une solution raisonnable est d’effectuer une campagne de test contenant un ensemble de tests réduit mais significatif permettant de trouver le nombre maximum d’erreurs ou de comportements non-conformes aux exigences dans le logiciel [79]. Pour générer des tests significatifs, il faut définir clairement quelles erreurs on souhaite détecter dans le logiciel, c’est-à-dire définir des objectifs de tests. Des objectifs de tests classiques pour la certification de logiciels embarqués sont par exemple :

• chaque exigence doit être testée au moins une fois,

• chaque opération doit être testée pour des valeurs de fonctionnement normal, resp. anormal, au moins une fois,

• la campagne de test doit atteindre la couverture des exigences par les critères de couverture MCDC, etc.

Les objectifs de tests permettent de déterminer les points précis que nous voulons atteindre dans le système pour vérifier la présence ou l’absence d’erreurs, auxquels nous associons un comportement attendu, c’est l’oracle de test. Ces objectifs peuvent être plus ou moins précis selon le niveau de description des fonctionnalités et les contraintes relatives à la certification du logiciel. La validation du système est donc limitée à un nombre fini d’objectifs de tests motivés par la recherche d’erreurs potentielles présentes dans le logiciel. Cependant, cette méthodologie permet d’associer à un objectif de test défini de façon précise et non-ambiguë des liens de traçabilité forts entre un test généré et l’exigence qui en est la source.

3.2.2 Déterminer les stimulations pour atteindre des points du système

La génération de tests se découpe donc en deux parties ; nous avons d’abord étudié la détermination des points du système à valider par le test. Nous nous intéressons

mainte-3.2 Méthodologie de la génération de tests

nant au problème de la génération de stimulations numériques fiables à partir des com-portement attendus identifiés précédemment. Déterminer une séquence de stimulations permettant d’atteindre un point spécifique du système revient à un problème de recherche de chemin dans un espace de configuration [80, 81]. C’est un problème difficile dû à la taille de cet espace, et à l’hétérogénéité des fonctionnalités décrites dans les exigences (booléennes/numériques, combinatoires/séquentielles, linéaires/non-linéaires) [82, 62].

Combiner une analyse de la propagation des erreurs de calcul pour pouvoir déterminer des stimulations numériques de manière fiable avec une analyse structurelle des états et transitions du système permettant d’atteindre le comportement attendu à observer dans le logiciel est un problème difficile [81], aussi bien pour des tests générés de façon automatique que manuelle. Le document de recommandations pour la certification de logiciels embarqués DO178–C [1] prévoit donc de remplacer la génération de certains tests par des activités de relecture et d’analyse (voir figure 1.3).

On peut donc envisager de développer un outil de génération automatique de tests exécutant plusieurs actions. À partir d’une spécification fonctionnelle formalisée traduite (à la main) depuis des exigences textuelles et d’objectifs de tests décrits dans ce même formalisme, l’outil détermine les points du système correspondant, c’est-à-dire les com-portements attendus. La deuxième étape est de générer les stimulations correspondantes permettant d’atteindre la configuration souhaitée dans le système pour vérifier les compor-tements attendus. L’outil peut s’arrêter avant d’avoir atteint le critère d’adéquation si l’une des deux étapes de génération de test est trop difficile à calculer, du moment qu’il informe l’utilisateur précisément sur les tests qui n’ont pas été générés.

3.2.3 Vérifier la qualité des tests

Cette dernière notion de fiabilité d’une campagne de test peut être quantifiée grâce au critère d’adéquation d’un ensemble de tests à une spécification fonctionnelle. Si on considère un ensemble d’exigences fonctionnelles E , on peut alors définir l’ensemble des programmesψ non-équivalents implémentés à partir de E, ce qui signifie que ces pro-grammes sont développés différemment et ne présentent potentiellement pas les mêmes fonctionnalités. Un ensemble de tests T est dit adéquat [83] pour le système d’exigences E relativement àψ si, pour chaque programme P ∈ ψ, P ne passe pas la campagne de test pour au moins un point de test, alors T a découvert une erreur dans P par rapport à E [83]. Si l’ensemble de programmesψ implémentés à partir de E est fini, alors E possède un ensemble de tests adéquat.

Définition 5 (Critère d’adéquation des tests [79, 84]). Un critère d’adéquation des tests est

En général, le critère d’adéquation des tests est un ensemble de règles dérivées des objectifs de test ; il est alors satisfait lorsque tous les objectifs de tests sont remplis par au moins un cas de test2. Dans la section 1.2.1 nous avons défini des critères recommandés d’évaluation de la qualité d’une campagne de tests pour la certification. L’ensemble de ces critères, correspondent aux objectifs de tests, forment donc le critère d’adéquation des tests. Ainsi le but de la génération d’une campagne de tests est de remplir le critère d’adéquation associé avec un nombre nécessaire et suffisant de tests, soit de remplir tous les objectifs de tests déterminés pour valider les fonctionnalités des exigences avec un minimum de tests. La génération de tests peut être apparentée à un problème d’optimisation [81].

3.2.4 Résoudre des problèmes d’optimisation combinatoire

Programmation par contraintes La programmation par contraintes [85] est un

para-digme de programmation dans lequel les relations entre les inconnues d’un problème, c’est-à-dire les variables, sont décrites sous la forme de contraintes, c’est-à-dire de rela-tions entre les variables limitant leurs domaines de définition. Le problème est de trouver des valeurs pour les variables satisfaisant toutes les contraintes du modèle. Un ensemble de valeurs associées aux variables sont dites cohérentes si elles forment une solution des contraintes. La recherche de solutions est effectuée par des solveurs de contraintes, dont la tâche consiste à éliminer les valeurs inconsistantes. La résolution de contraintes pour la génération de tests numériques est utilisée dans plusieurs outils de génération de tests pour la vérification et validation de logiciels critiques. On compte notamment l’outil GaTel [86], développé par la Commissariat à l’énergie atomique (CEA) se basant sur une représenta-tion en Lustre d’une spécificareprésenta-tion du logiciel, et manipulant des variables booléennes et entières. On remarque également le cadre applicatif FPCS [87] qui propose de générer des tests pour des intervalles à partir d’un programme annoté. Les tests visent à vérifier les intervalles où le comportement du programme pourrait ne pas être conforme à un modèle manipulant des nombres réels.

Satisfaisabilité modulo théories (SMT) Un problème SAT (pour satisfaisabilité),

s’expri-mant grâce à une formule de logique propositionnelle, s’attache à déterminer s’il existe une configuration des variables propositionnelles satisfaisant ce problème, c’est-à-dire rendant la formule vraie [88]. Un problème SMT est une généralisation du problème SAT à la logique du premier ordre, étendue avec des symboles de fonction et de prédicat particu-liers, formant des théories. Un problème SMT peut donc décrire, par exemple, la théorie de l’arithmétique linéaire sur les entiers (LIA) ou la théorie des tableaux (Array). La tech-nique SMT repose sur des procédures de décision, soit des petits algorithmes de preuve