Logo Parasoft

En savoir plus sur le test Parasoft C/C++.

Rejoignez notre démo de produit mensuelle de 30 minutes.

Inscrivez-vous

WEBINAIRE

Ce que vous devez savoir sur la couverture du code pour les systèmes C/C++ embarqués

La couverture de code mesure la quantité de code source d'une application testée par diverses méthodes, telles que les tests unitaires, les tests manuels et les tests fonctionnels automatisés. Les objectifs de pourcentage de couverture de code peuvent être subjectifs. L'exhaustivité de la couverture dans les systèmes critiques pour la sécurité dépend du niveau d'intégrité de sécurité (SIL) utilisé dans différents secteurs et du niveau d'assurance de conception (DAL) couramment utilisé en avionique. Pour la conception d'applications critiques pour la sécurité où une défaillance peut entraîner la mort, les normes réglementaires et industrielles exigent une couverture de code structurelle de 100 %.

Cette présentation aborde le sujet essentiel de la couverture de code pour les systèmes C/C++ embarqués, en expliquant son importance, les différents types de mesures et son application pratique. Nous explorons comment réaliser des tests approfondis, notamment dans les environnements critiques pour la sécurité, et présentons des outils qui simplifient le processus.

Comprendre la couverture du code

La couverture de code est une mesure qui indique la quantité de code source de votre application exécutée pendant les tests. Elle permet de répondre à la question : « Avons-nous suffisamment testé ? » En mettant en évidence le code non testé, elle permet de détecter les bugs potentiels et d'identifier le code mort. La méthode la plus courante pour y parvenir est l'instrumentation du code, qui consiste à ajouter du code supplémentaire pour suivre l'exécution des instructions, des décisions ou des branches. Cette instrumentation enregistre ensuite l'exécution, permettant ainsi de calculer et de visualiser un pourcentage de couverture de code, souvent avec le code surligné en vert (exécuté) ou en rouge (non exécuté).

Critères de couverture clés

  • Couverture du relevé : Garantit que chaque instruction de l'application a été exécutée.
  • Couverture de la ligne : Vérifie si chaque ligne de code a été exécutée. Le résultat peut différer de la couverture de l'instruction si plusieurs instructions sont présentes sur une même ligne.
  • Couverture des succursales (couverture des décisions) : Vérifie que chaque chemin d'exécution possible après un point de décision (comme une instruction if) est utilisé au moins une fois. Cela implique de vérifier que les résultats vrais et faux des conditions sont testés.
  • Couverture de condition/décision modifiée (MC/DC) : Une norme plus rigoureuse, notamment pour les systèmes critiques pour la sécurité, exige que chaque condition d'une décision ait été démontrée comme affectant indépendamment le résultat de la décision. Cela implique de tester tous les résultats possibles pour chaque condition et de s'assurer que chaque condition peut modifier le résultat de la décision.
  • Couverture de conditions multiples (MCC) : Teste toutes les combinaisons possibles de résultats pour les conditions des décisions. Bien que rigoureux, ce test peut engendrer un nombre très élevé de cas de test.

Points saillants de la démonstration pratique

La présentation comprenait une démonstration présentant :

  • Génération automatisée de cas de test unitaire : Les outils peuvent générer automatiquement de nombreux tests unitaires pour aider à atteindre les objectifs de couverture.
  • Analyse de la couverture : Visualisation des métriques de couverture (ligne, instruction, branche, MC/DC) dans des IDE comme Eclipse, VS Code ou via des outils de ligne de commande autonomes.
  • Champ d'application : Utilisation d'outils de ligne de commande pour instrumenter et collecter des données de couverture pour des applications autonomes, qui peuvent ensuite être importées dans un IDE pour analyse.
  • Test du matériel cible : La possibilité d'effectuer une analyse de couverture sur des cibles intégrées, avec des optimisations de taille et de vitesse, et la prise en charge des applications multithread.
  • Reporting: Génération de rapports et publication de données de couverture sur des plateformes telles que DTP (Development Testing Platform) pour une analyse et un tableau de bord centralisés.

Pourquoi les types de couverture spécifiques sont importants dans les systèmes embarqués

Dans le monde embarqué, C et C++ sont fréquemment utilisés dans les systèmes critiques pour la sûreté et la sécurité. Des secteurs comme l'automobile (ISO 26262), l'avionique (DO-178C) et les dispositifs médicaux (CEI 62304) ont des exigences réglementaires et des normes de processus strictes. Ces normes attribuent souvent des niveaux d'intégrité de sécurité (SIL) ou des niveaux d'assurance de conception (DAL) aux composants logiciels. Des niveaux plus élevés, indiquant un risque accru en cas de défaillance du logiciel, exigent généralement des tests plus rigoureux. Par exemple, le niveau SIL 4 de la norme CEI 61508 recommande fortement une couverture à 100 % pour les instructions, les branches et les MC/DC. Le point commun de ces normes est l'accent mis sur la couverture des instructions, des branches et des MC/DC, car ces normes sont considérées comme les meilleures pratiques par les experts du secteur pour garantir un code de haute qualité, sûr, sécurisé et fiable.

Méthodes d'obtention de la couverture du code

Atteindre la couverture du code peut être réalisé par différentes méthodes de test :

  • Test du système : L'exécution de cas de test système existants sur du code instrumenté peut assurer une couverture significative avec un minimum d'effort supplémentaire. Cependant, cette couverture est souvent inférieure à 100 %, notamment pour le code défensif qui ne s'exécute qu'en cas de panne.
  • Test unitaire La création de tests unitaires spécifiques peut cibler le code non couvert, y compris le code défensif ou des branches spécifiques, pour atteindre des objectifs de couverture plus élevés.
  • Test manuel : Bien que moins automatisée, l’exécution manuelle des tests peut également contribuer aux mesures de couverture.

De nombreuses organisations combinent les résultats de ces différentes méthodes de test pour atteindre leurs objectifs de couverture globale. Par exemple, la couverture des tests unitaires peut être fusionnée avec celle des tests système.

Intégration de la couverture dans CI/CD

La couverture du code est un élément essentiel d'un pipeline d'intégration/livraison continue (CI/CD). Les outils permettent d'automatiser l'instrumentation, l'exécution et le reporting des données de couverture, en s'intégrant parfaitement aux systèmes de build et aux plateformes CI/CD comme Jenkins, GitLab et Azure DevOps. Cela permet d'obtenir un retour d'information en temps réel sur la qualité du code et de gérer efficacement les risques.

Gérer les défis liés à la couverture du code

  • Code inaccessible : Parfois, en raison de boucles infinies ou de structures de code spécifiques, certaines instructions peuvent être impossibles à atteindre par des tests normaux. Dans ce cas, couverture par inspection (la vérification visuelle de l'exécution, généralement par débogage) est une approche recommandée pour satisfaire aux normes.
  • Gonflement du code : L'instrumentation peut augmenter la taille de l'exécutable. Si cela empêche l'application de s'adapter au matériel cible, une pratique courante consiste à instrumenter la moitié du code, à collecter la couverture, puis à instrumenter l'autre moitié et à fusionner les résultats.
  • Couverture au niveau de l'assemblage: Pour les systèmes à haute assurance (comme la norme DO-178C niveau A), une couverture au niveau du code assembleur ou objet est requise, car les compilateurs peuvent générer du code non directement traçable jusqu'à la source. Des outils existent pour automatiser ce processus.

En définitive, la couverture de code est une technique puissante pour garantir la qualité et la fiabilité des systèmes C/C++ embarqués, notamment dans les domaines critiques pour la sécurité. En comprenant les différents critères de couverture et en exploitant les outils appropriés, les équipes de développement peuvent atteindre leurs objectifs de test plus efficacement.