Logo pour GIGAOM 365x70

Découvrez quelle solution de test API est arrivée en tête dans le rapport GigaOm Radar. Obtenez votre rapport d'analyse gratuit >>

Conformité logicielle DO-178C pour l'aérospatiale et la défense

Couverture du code structurel

Recueillir et analyser métriques de couverture de code est un aspect important du développement de logiciels critiques pour la sécurité. La couverture du code mesure l'achèvement des cas de test et des tests exécutés. Elle fournit la preuve que la vérification est complète, au moins comme spécifié par la conception du logiciel. Les objectifs de l'analyse de la couverture des tests incluent l'atteinte des cibles de couverture des tests suivantes :

Cercle bleu avec une icône de coche blanche au centre.

Exigences de haut niveau

Cercle bleu avec une icône de coche blanche au centre.

Exigences de bas niveau

Cercle bleu avec une icône de coche blanche au centre.

Structure du logiciel selon les critères de couverture appropriés

Cercle bleu avec une icône de coche blanche au centre.

Structure du logiciel, couplage des données et couplage du contrôle

Icône à l'intérieur d'un cercle bleu montrant un contour blanc d'une liste de contrôle des directives.

Section 6.4.4.1

La section 178 de la norme DO-6.4.4.1C porte sur l'analyse de la couverture des tests d'exigences, qui détermine dans quelle mesure les tests fonctionnels ont vérifié la mise en œuvre des exigences. Il est prévu que l'analyse de la couverture du code soit collectée au cours de ces tests et que les lacunes restantes dans la couverture du code soient comblées par des tests supplémentaires.

Icône à l'intérieur d'un cercle bleu montrant un contour blanc d'une liste de contrôle des directives.

Section 6.4.4.2

La section 6.4.4.2 exige une analyse pour déterminer ce qui reste de la couverture du code, y compris les interfaces entre les composants. La section 6.4.4.3 décrit les exigences pour combler les lacunes de couverture, y compris l'identification du code étranger, mort et désactivé.

La manière dont cela se traduit en types et en quantités de couverture est quelque peu sujette à interprétation. Cependant, dans le développement de logiciels aéroportés, il incombe au fabricant de planifier la couverture du code, de respecter le plan, de le documenter et de le terminer.

Types de couverture de code

Voici les différents types de couverture de code.

Couverture de l'état

La couverture des instructions nécessite que chaque instruction de programme soit exécutée au moins une fois. La couverture des branches et des MC/DC englobe la couverture des instructions.

Couverture de la succursale

La couverture des branches garantit que chaque branche de décision (constructions if-then-else) est exécutée.

Couverture de condition/décision modifiée (MC/DC)

La couverture conditionnelle/décision modifiée (MC/DC) nécessite la couverture de code la plus complète pour garantir que les cas de test exécutent chaque branche de décision et toutes les combinaisons possibles d'entrées qui affectent le résultat de la logique de décision. Pour une logique complexe, le nombre de cas de test peut exploser, c'est pourquoi les restrictions de condition modifiée sont utilisées pour limiter les cas de test à ceux qui entraînent une modification des expressions logiques autonomes.

Code exécutable/objet

Un code exécutable/objet est requis si le critère de niveau logiciel est A. Cela est dû au fait qu'un compilateur ou un éditeur de liens génère un code assembleur supplémentaire qui n'est pas directement traçable aux instructions du code source. Par conséquent, une couverture au niveau objet doit être effectuée.

Avancé outils d'automatisation des tests unitaires, comme Parasoft C/C++test, fournit toutes ces mesures de couverture de code et bien plus encore. C/C++test CT automatise également cette collecte de données sur les tests de l'hôte et de la cible et accumule l'historique de la couverture des tests au fil du temps. Cet historique de couverture de code peut couvrir les tests unitaires, d'intégration et système pour garantir que la couverture est complète et traçable à tous les niveaux de test.

Photo montrant un gros plan du cockpit d'une navette spatiale.

Couverture des tests du système

L'obtention d'une couverture de code via des tests système est une excellente méthode pour déterminer si suffisamment de tests ont été effectués. L'approche consiste à exécuter tous vos tests système, puis à examiner les parties du code qui n'ont pas été testées.

Le code non exécuté implique qu'il peut être nécessaire de lancer de nouveaux cas de test pour tester le code intact, là où un défaut peut se cacher et aider à répondre à la question : ai-je effectué suffisamment de tests ?

Lorsque les équipes effectuent des tests système, la mesure moyenne obtenue est de 60 % de couverture. Une grande partie des 40 % de code non exécuté est due au code défensif de votre application. Le code défensif ne s'exécute que lorsque le système déclenche une erreur ou entre dans un état problématique qui peut être difficile à produire. Des conditions telles que des fuites de mémoire ou d'autres types d'erreurs causées par une défaillance matérielle peuvent prendre des semaines, des mois ou des années à se produire.

Il existe également du code défensif imposé par vos directives de codage où les cas de test système ne peuvent jamais vous amener à exécuter. Pour ces raisons, les tests système ne peuvent pas vous permettre d'atteindre une couverture de code structurel à 100 %. Vous devrez utiliser d'autres méthodes de test comme les tests manuels et/ou unitaires pour atteindre 100 %.

Couverture des tests unitaires

Comme mentionné précédemment, les tests unitaires peuvent être utilisés comme une approche complémentaire aux tests système pour obtenir une couverture à 100 %. L'obtention d'une couverture de code via des tests unitaires est l'une des méthodes les plus populaires utilisées, mais elle n'indique pas si vous avez effectué suffisamment de tests du système, car l'accent est mis au niveau de l'unité (fonction/procédure).

L'objectif ici est de créer un ensemble de cas de test unitaires qui exercent l'unité entière sur la couverture requise (instruction, branche et MC/DC) afin d'atteindre une couverture de 100 % pour cette unité unique. Cette opération est répétée pour chaque unité jusqu'à ce que l'ensemble de la base de code soit couvert. Cependant, pour tirer le meilleur parti des tests unitaires, ne vous concentrez pas uniquement sur l'obtention d'une couverture de code. Cela peut généralement être accompli grâce à des cas de test de scénario de journée ensoleillée.

Entraînez réellement l'unité à travers des scénarios de jours ensoleillés et pluvieux pour garantir la robustesse, la sécurité, la sûreté et la traçabilité des exigences de bas niveau. Laissez la couverture du code être un sous-produit de vos cas de test et complétez la couverture si nécessaire.

Pour accélérer la couverture du code via les tests unitaires, des fonctionnalités de génération de cas de test configurables et automatisées existent dans Parasoft C/C++test. Les cas de test peuvent être générés automatiquement pour tester l'utilisation de pointeurs nuls, de plages min-mid-max, de valeurs limites et bien plus encore. Cette automatisation peut vous mener loin. En quelques minutes, vous obtiendrez une couverture de code substantielle.

Capture d'écran du code pour un retour inaccessible 0 ; Déclaration
Retour inaccessible 0 ; Déclaration

De plus, C/C++test CT étend les flux de travail de développement avec la couverture du code en s'intégrant aux frameworks de tests unitaires et aux IDE propriétaires. Intégrez étroitement la ligne de couverture du code, l'instruction, la condition simple, la décision, la branche, la fonction, l'appel et MC/DC avec des frameworks de tests unitaires propriétaires comme GoogleTest et CppUnit et des IDE comme VS Code.

Cependant, comme dans les tests système, il est difficile d'obtenir une couverture de code à 100 % en raison de l'utilisation d'un code défensif ou d'une sémantique de langage formel. Au niveau granulaire d'une unité, le code défensif peut se présenter sous la forme d'une instruction par défaut dans un commutateur. Si tous les cas possibles dans un commutateur sont capturés, cela rend l'instruction par défaut inaccessible. Dans l'exemple ci-dessous, le retour 0; ne sera jamais exécuté car le while (1) est infini.

Comment obtenir une couverture à 100% pour ces cas particuliers ?

Réponse : Déploiement de méthodes manuelles.

Suivez ces étapes.

  1. Étiquetez ou notez l'instruction comme couverte à l'aide d'un débogueur.
  2. Modifiez la pile d’appels et exécutez l’instruction return 0;.
  3. Soyez témoin visuel de l’exécution et, au minimum, documentez le nom du fichier, la ligne de code et l’instruction de code qui est désormais considérée comme couverte.

Cette couverture réalisée via une inspection manuelle/visuelle et des rapports peut être utilisée pour compléter la couverture capturée via les tests unitaires. L'ajout des deux rapports de couverture peut être utilisé pour prouver une couverture à 100 % du code structurel.

L’objectif d’obtenir une couverture de code est un moyen supplémentaire de contribuer à garantir la sécurité, la sûreté et la fiabilité du code.

Instrumentation de code

La couverture du code est le plus souvent identifiée en instrumentant le code. Instrumenté fait référence au fait d'avoir le code utilisateur agrémenté de code supplémentaire pour vérifier pendant l'exécution si cette instruction, branche ou MC/CD a été exécuté.

En fonction de la cible ou du système testé, les données de couverture peuvent être stockées dans le système de fichiers, écrites en mémoire ou envoyées via divers canaux de communication, tels que le port série, le port TCP/IP, l'USB et même le JTAG.

Instrumentation partielle

Gardez à l'esprit que l'instrumentation du code entraîne un gonflement du code. L'augmentation de la taille du code peut avoir un impact sur la capacité à charger le code sur un matériel cible à mémoire limitée pour les tests.

La solution de contournement consiste à instrumenter une partie du code en suivant ces étapes :

  1. Exécutez vos tests et capturez la couverture.
  2. Instrumentez l'autre partie du code.
  3. Exécutez à nouveau vos tests.
  4. Capturez la couverture.
  5. Fusionner la couverture de la précédente exécution du test.

Conseiller en couverture

Parasoft C/C++test résout les lacunes de couverture dans les suites de tests. Parasoft a découvert comment utiliser l'analyse de code statique avancée (analyse de flux de données et de contrôle) pour trouver les valeurs des paramètres d'entrée requis pour exécuter des lignes spécifiques de code non couvert.

Dans un code complexe, il y a toujours des instructions de code insaisissables pour lesquelles il est extrêmement difficile d'obtenir une couverture. Il est probable qu'il y ait plusieurs valeurs d'entrée avec diverses permutations et chemins possibles qui rendent le déchiffrage compliqué et long. Mais une seule combinaison peut vous offrir la couverture dont vous avez besoin. Parasoft facilite l'obtention d'une couverture de ces lignes de code difficiles à atteindre.

Lorsque vous sélectionnez la ligne de code que vous souhaitez couvrir, le conseiller de couverture vous indique les valeurs d'entrée, les variables globales et les appels externes dont vous avez besoin pour stimuler le code et obtenir une couverture.

Capture d'écran de Parasoft C/C++test Coverage Advisor.
Appeler Coverage Advisor en cliquant avec le bouton droit sur la ligne de code.
Capture d'écran montrant deux solutions de cas de test fournies par Coverage Advisor dans le test C/C++.
Deux solutions de cas de test fournies par Coverage Advisor.

La figure de droite montre un rapport d'analyse fournissant à l'utilisateur une solution. Le champ Conditions préalables exprime :

  • La plage et les valeurs d'entrée pour mainSensorSignal et coSensorSignal
  • Les résultats attendus des appels externes

Lors de la création du cas de test unitaire avec ces valeurs de paramètres définies et ces stubs pour les appels externes, vous obtenez une couverture de la ligne sélectionnée, ainsi que les lignes supplémentaires exprimées dans le champ Couverture attendue.


Couverture du code objet

Capture d'écran de Parasoft ASMTool pour la couverture du code assembleur/objet
Parasoft ASMTool pour la couverture du code assembleur/objet

Pour les applications critiques de sécurité les plus strictes, la couverture du code objet DO-178C niveau A est requise. Par conséquent, la couverture du niveau d'assemblage doit être effectuée. Imaginez la rigueur et le coût de la main-d'œuvre nécessaires à l'exécution de cette tâche. Heureusement, Parasoft ASMTools fournit une solution automatisée pour obtenir la couverture du code objet.

Bannière bleu foncé avec l'image d'un homme parlant à une femme tenant une tablette à la main dans une salle de serveurs.
Image d'un homme et d'une femme avec une tablette à la main en train de discuter dans une salle de serveurs.

Améliorez vos tests logiciels avec les solutions Parasoft.