Vérification dynamique : tests unitaires
La vérification dynamique consiste à exécuter le logiciel à l’aide de cas de test définis et à mesurer son comportement réel en exécution. Elle permet de s’assurer que les fonctions renvoient des résultats corrects dans des conditions normales, dans des cas limites et dans des états d’erreur, et génère les données de couverture structurelle exigées par les normes ISO 26262, DO-178C, CEI 61508 et CEI 62304 à titre de preuve de vérification.
C’est par les tests unitaires que ce processus commence. Chaque fonction, module, classe et composant est vérifié de manière isolée par rapport à sa spécification avant le début de l’intégration. Les défauts détectés à ce stade coûtent une fraction de ceux détectés lors de l’intégration ou sur le terrain, et les enregistrements de traçabilité générés ici constituent la base du dossier de conformité.
Le processus de test
Le processus de vérification dynamique dans le cadre du développement de systèmes critiques pour la sécurité suit une séquence définie. Avant le début des tests, les exigences sont importées et associées aux cas de test, ce qui établit la traçabilité de base requise par la norme applicable. Les environnements de test isolent le logiciel testé à l’aide de stubs et de mocks afin de remplacer les dépendances indisponibles. Les tests s’exécutent sur l’hôte, la cible ou les deux, et leur couverture est mesurée tout au long du processus. Les résultats sont réintégrés dans le système de gestion des exigences, complétant ainsi la trace bidirectionnelle examinée par les auditeurs.
Ce que les tests unitaires permettent de vérifier
Une suite complète de tests unitaires ne se limite pas à vérifier les entrées attendues. Chaque cas de test est rédigé en fonction d'une exigence spécifique et couvre :
- Entrées normales et résultats attendus
- Conditions aux limites et cas « off-by-one »
- Entrées erronées et états non valides
- Conditions de débordement et de sous-débordement propres aux types de données concernés
Comportement lorsque les dépendances renvoient des valeurs inattendues
Dans le développement de systèmes critiques pour la sécurité, chaque cas de test est rattaché à une exigence spécifique qu’il est censé vérifier. La traçabilité bidirectionnelle de l’exigence au cas de test puis au résultat constitue une preuve obligatoire au titre des normes DO-178C et ISO 26262.
Traçabilité des exigences
Les tests basés sur les exigences sont obligatoires en vertu des normes ISO 26262, DO-178C, CEI 61508 et CEI 62304. Chaque cas de test doit pouvoir être rattaché à une exigence spécifique qu’il est censé vérifier, et les résultats des tests doivent être reliés à ces exigences de manière bidirectionnelle. Ce document atteste que toutes les exigences ont été testées et qu’il n’existe aucun test sans exigence correspondante.
La passerelle« Requirements Gateway » de VectorCAST se connecte à des bases de données d’exigences externes, importe les exigences dans l’environnement de test et permet de relier directement les cas de test à celles-ci. Une fois l’exécution terminée, les résultats et les indicateurs de couverture sont réexportés vers l’outil de gestion des exigences. Les exigences non couvertes par les tests sont immédiatement visibles, tout comme les cas de test ne comportant aucune exigence associée.
Mise en place de l'environnement de test
Les logiciels embarqués soumis à des tests dépendent généralement d’interfaces matérielles, de services du système d’exploitation ou d’autres composants logiciels qui ne sont pas disponibles ou qu’il n’est pas pratique d’invoquer lors des tests unitaires. Les stubs remplacent ces dépendances, ce qui permet de tester l’unité sous test de manière isolée, tout en conservant un contrôle total sur les valeurs renvoyées par chaque dépendance.
VectorCAST génère automatiquement des stubs pour toutes les dépendances lors de la création d’un environnement de test. Les stubs peuvent être activés, désactivés ou configurés pour chaque cas de test afin de renvoyer des valeurs spécifiques. Les points de sondage étendent encore ce contrôle, en permettant d’injecter des valeurs à n’importe quel endroit de l’unité testée afin d’atteindre des chemins de code qui, autrement, nécessiteraient des conditions matérielles spécifiques ou des états de défaillance pour être déclenchés. VectorCAST prend également en charge la création de stubs pour les instanciations de fonctions-modèles, y compris les instanciations explicites et implicites des membres de classes-modèles, ce qui est important pour les bases de code C++ où ce modèle est courant.
Couverture du code
La couverture de code mesure la proportion du code exécutable qui est testée par la suite de tests. Les normes de sécurité prescrivent des niveaux de couverture minimaux en fonction du degré de criticité du logiciel en cours de développement.
- La couverture des instructions garantit que chaque ligne d’exécution a été exécutée au moins une fois
- La couverture des branchements confirme que chaque point de décision a pris chacune des issues possibles
- La couverture MC/DC (Modified Condition/Decision Coverage) prouve que chaque condition booléenne d’une décision influence indépendamment le résultat ; il s’agit du critère structurel le plus rigoureux et d’une exigence pour les logiciels conformes à la norme DO-178C niveau A et à la norme ISO 26262 ASIL D
VectorCAST mesure tous ces types de couverture et intègre des « modes industriels » qui sélectionnent automatiquement les critères de couverture adaptés à une norme et à un niveau d’intégrité de sécurité donnés. Les résultats de couverture sont certifiés par le TÜV.
Tests sur l'hôte et la cible
Les tests unitaires sont généralement développés et exécutés en premier lieu sur la machine hôte, pour des raisons de rapidité et de contrôle. Les itérations rapides, le retour d’information immédiat et la facilité de débogage font de la machine hôte l’environnement idéal pour créer et affiner la suite de tests. Lors des tests sur la machine hôte, le compilateur cible n’est pas utilisé ; tout comportement spécifique au compilateur doit donc être vérifié séparément sur la cible.
VectorCAST permet d’exécuter très simplement les mêmes cas de test sur le matériel cible. Les environnements de test sont développés sur l’hôte et exécutés sur la cible à l’aide de Runtime Support Packages (RSP) disponibles pour de nombreux compilateurs croisés et systèmes d’exploitation en temps réel. La mesure de la couverture, la traçabilité et la génération de rapports s’appliquent de la même manière dans les deux environnements.
Génération automatisée de tests
La rédaction manuelle de cas de test pour une base de code embarqué volumineuse est chronophage et susceptible de présenter des lacunes. La fonctionnalité de génération automatisée de tests (ATG) de VectorCAST produit un ensemble initial de cas de test directement à partir du code source, en ciblant les conditions limites et les chemins d’exécution que la rédaction manuelle omet souvent. Les ingénieurs examinent et complètent les tests générés plutôt que de les rédiger à partir de zéro.
Les équipes qui préfèrent écrire directement le code de test peuvent utiliser les « Coded Tests », qui permettent la rédaction de tests de type xUnit à l’aide d’une syntaxe compatible avec GoogleTest, tout en conservant l’accès aux fonctionnalités de VectorCAST en matière de mesure de couverture, de traçabilité et d’intégration CI/CD.
VectorCAST
VectorCAST est la plateforme de tests dynamiques et d'automatisation des tests de Vector destinée aux logiciels embarqués en C, C++ et Ada. Elle automatise la mise en place de l'environnement de test, génère et gère les cas de test, exécute les tests sur l'hôte et la cible, mesure la couverture structurelle et produit des rapports vérifiables.
Ses principales fonctionnalités sont les suivantes :
- Configuration automatique de l’environnement de test avec génération de stubs, de mocks et de harnais de test
- Génération automatisée de tests (ATG) pour produire des cas de test initiaux directement à partir du code source
- Tests codés pour la création de tests de type xUnit, compatibles avec la syntaxe GoogleTest
- Passerelle d’exigences pour une traçabilité bidirectionnelle vers des bases de données d’exigences externes
- Tests basés sur les modifications pour réexécuter uniquement les tests affectés par les modifications du code
- ExtensionVectorCAST Test Explorer pour Visual Studio Code
- Intégration CI/CD, notamment avec Jenkins, Azure DevOps et GitLab