web-dev-qa-db-fra.com

Test intégré des logiciels embarqués

Quelles meilleures pratiques avez-vous utilisées dans les tests unitaires de logiciels embarqués propres aux systèmes embarqués?

61
Brandon E Taylor

Les logiciels intégrés peuvent avoir parcouru un long chemin au cours des 10 dernières années, mais nous avons généralement fait ce qui suit:

  • pour les algorithmes qui ne dépendent pas du matériel cible, nous avons simplement eu des tests unitaires qui ont été construits et testés sur une plate-forme non intégrée.
  • pour les choses qui nécessitaient le matériel, les tests unitaires étaient conditionnellement compilés dans le code pour utiliser le matériel disponible. Dans notre cas, c'était un port série sur la cible poussant les résultats vers une autre machine, plus capable, où les tests étaient vérifiés pour l'exactitude.
  • Selon le matériel, vous pouvez parfois simuler un périphérique "virtuel" sur une plate-forme non intégrée. Cela consistait généralement à avoir un autre thread d'exécution (ou fonction de signal) changeant la mémoire utilisée par le programme. Utile pour les E/S mappées en mémoire mais pas les IRQ et autres.
  • en règle générale, vous ne pouvez tester qu'uniquement un petit sous-ensemble du code complet à la fois (en raison de contraintes de mémoire).
  • pour tester des choses sensibles au temps, nous ne l'avons pas fait. Clair et simple. Le matériel que nous avons utilisé (8051 et 68302) n'était pas toujours fonctionnel s'il fonctionnait trop lentement. Ce type de débogage devait être fait initialement avec un CRO (oscilloscope) et (quand nous avions plus d'argent) un ICE (émulateur en circuit).

J'espère que la situation s'est améliorée depuis la dernière fois que je l'ai fait. Je ne souhaiterais pas cette douleur à mon pire ennemi.

51
paxdiablo

Il peut y avoir beaucoup à gagner en testant les unités dans un environnement PC (en compilant votre code avec un compilateur PC C et en exécutant votre code dans un framework de tests unitaires PC), avec plusieurs conditions:

  1. Cela ne s'applique pas au test de votre code de bas niveau, y compris le code de démarrage, RAM, pilotes matériels. Vous devrez utiliser des tests unitaires plus directs de ceux-ci.
  2. Le compilateur de votre système intégré doit être digne de confiance, donc vous ne recherchez pas les bogues créés par le compilateur.
  3. Votre code doit être une architecture en couches, avec abstraction matérielle. Vous devrez peut-être écrire des simulateurs de pilotes matériels pour votre infrastructure de test d'unité PC.
  4. Vous devez toujours utiliser le stdint.h types tels que uint16_t plutôt que simple unsigned int etc.

Nous avons suivi ces règles et avons constaté qu'après avoir testé le code de la couche application dans un cadre de test unitaire PC, nous pouvons être sûrs que cela fonctionne bien.

Avantages des tests unitaires sur la plate-forme PC:

  1. Vous ne rencontrez pas le problème de manquer d'espace ROM sur votre plate-forme intégrée en raison de l'ajout d'un cadre de test unitaire.
  2. Le cycle d'exécution de la liaison de compilation est généralement plus rapide et plus simple sur la plate-forme PC (et évite l'étape "écriture/téléchargement" qui peut potentiellement durer plusieurs minutes).
  3. Vous avez plus d'options pour visualiser la progression (certaines applications intégrées ont des périphériques d'E/S limités), stocker les données d'entrée/sortie pour l'analyse, exécuter des tests plus longs.
  4. Vous pouvez utiliser des frameworks de test unitaire sur PC facilement disponibles qui ne sont pas disponibles/adaptés à une plate-forme intégrée.
20
Craig McQueen

Les systèmes embarqués sont un sujet vaste mais en général, considérons-le comme un produit spécifique qui combine à la fois le matériel et le logiciel. Mon expérience embarquée vient des téléphones portables qui ne sont qu'un petit sous-ensemble de tous les systèmes embarqués. Je vais essayer de garder un peu les points suivants du côté abstrait:

  • Dans la mesure du possible, résumez les dépendances matérielles. De cette façon, vous pouvez exécuter vos tests unitaires sur du "matériel" simulé et également tester divers cas rares/exceptionnels qui seraient plus difficiles à tester sur la cible. Pour éviter les coûts d'abstraction, vous pouvez utiliser par exemple compilation conditionnelle.

  • Avoir le moins possible dépend du matériel.

  • Les tests unitaires exécutés sur un émulateur ou un environnement de compilateur croisé ne garantissent toujours pas que le code fonctionne sur le matériel cible. Vous devez également tester sur la cible. Testez sur la cible le plus tôt possible.

13
laalto

Vous voudrez peut-être consulter Développement piloté par les tests pour Embedded C par James W. Grenning. Le livre devrait être publié en août 2010, mais le livre bêta est disponible dès maintenant sur The Pragmatic Bookshelf .

13
Matthew Rankin

Nous réussissons à faire tester un peu de code dépendant du matériel à l'aide d'un simulateur, nous utilisons le simulateur de Keil et IDE (non affilié, utilisez simplement leurs outils). Nous écrivons les scripts du simulateur pour piloter le 'matériel' "d'une certaine manière, nous nous attendons à ce qu'il réagisse et nous sommes en mesure de tester de manière assez fiable notre code de travail. Certes, cela peut prendre un certain effort pour modéliser le matériel pour certains tests, mais pour la plupart des choses, cela fonctionne très bien et nous permet d'obtenir beaucoup fait sans aucun matériel disponible. Nous avons pu obtenir un système presque complet fonctionnant dans le simulateur avant d'avoir accès au matériel et avons eu très peu de problèmes à traiter une fois que le code a été mis sur la réalité. Cela peut également accélérer considérablement la production de code puisque tout peut être fait sur le PC avec le débogueur plus approfondi disponible tout en simulant la puce vs en essayant de tout faire sur le matériel.

Nous avons réussi à faire en sorte que cela fonctionne de manière fiable pour les systèmes de contrôle complexes, les interfaces mémoire, les circuits intégrés personnalisés SPI et même un affichage mono).

6
radix07

Voix d'inexpérience ici, mais c'est quelque chose auquel j'ai aussi pensé récemment. Il me semble que la meilleure approche serait soit

A) Écrivez autant de votre code d'application indépendant du matériel que possible dans un environnement PC, avant de l'écrire sur la cible, et écrivez vos tests unitaires en même temps (le faire d'abord sur le PC devrait vous obliger à séparer les éléments indépendants du matériel). De cette façon, vous pouvez utiliser votre choix de testeurs d'unité, puis tester les éléments dépendants du matériel à l'ancienne - avec des oscilloscopes RS-232 et/ou et des broches d'E/S signalant des données dépendant du temps, selon la vitesse à laquelle il doit s'exécuter .

B) Tout écrire sur le matériel cible, mais avoir une cible make pour compiler conditionnellement un build de test unitaire qui exécutera des tests unitaires et produira les résultats (ou les données qui peuvent être analysées pour les résultats) via RS-232 ou tout autre moyen. Si vous n'avez pas beaucoup de mémoire, cela peut être délicat.

Edit 7/3/2009 Je viens d'avoir une autre réflexion sur la façon de tester les éléments dépendants du matériel. Si vos événements matériels se produisent trop rapidement pour être enregistrés avec RS-232, mais que vous ne voulez pas parcourir manuellement des tonnes de données d'oscilloscope en vérifiant si vos drapeaux de broches d'E/S montent et descendent comme prévu, vous pouvez utiliser un PC carte avec DIO intégré (comme la gamme de cartes d'acquisition de données de National Instruments) pour évaluer automatiquement la synchronisation de ces signaux. Il vous suffirait alors d'écrire le logiciel sur votre PC pour contrôler la carte d'acquisition de données à synchroniser avec le test unitaire en cours d'exécution.

6
Sam Skuce

Il y a beaucoup de bonnes réponses ici, certaines choses qui n'ont pas été mentionnées sont d'exécuter du code de diagnostic afin de:

    Consigner les événements HAL (interruptions, messages de bus, etc.)
    Ayez du code pour garder une trace de vos ressources (tous les sémaphores actifs, l'activité des threads)
    Avoir un mécanisme de capture ram pour copier le contenu du tas et de la mémoire sur un stockage persistant (disque dur ou équivalent) pour détecter et déboguer les interblocages, les livelocks, les fuites de mémoire, les débordements de tampon, etc.
3
embdeddCoder

Lorsque j'y ai fait face l'année dernière, je voulais vraiment tester sur la plate-forme embarquée elle-même. Je développais une bibliothèque et j'utilisais les appels RTOS et d'autres fonctionnalités de la plate-forme intégrée. Il n'y avait rien de spécifique disponible, j'ai donc adapté le code UnitTest ++ à mes besoins. Je programme sur le NetBurner famille et comme il a un serveur web intégré, il était assez simple d'écrire un lanceur de test GUI basé sur le web qui donne le feedback ROUGE/VERT classique. Il s'est avéré assez bien , et maintenant les tests unitaires sont beaucoup plus faciles et je me sens beaucoup plus confiant de savoir que le code fonctionne sur le matériel réel. J'utilise même le cadre de tests unitaires pour faire des tests d'intégration. Au début, je moque/stub le matériel et injecte cette interface à test. Mais finalement, j'écris des tests man-in-the-loop qui exercent le matériel réel. Il s'avère être un moyen beaucoup plus simple de se renseigner sur le matériel et d'avoir un moyen facile de récupérer des pièges intégrés. exécuter à partir de AJAX rappels au serveur Web un piège se produit uniquement à la suite de la facturation manuelle testez et le système redémarre toujours proprement quelques secondes après le piège.

NetBurner est suffisamment rapide pour que le cycle de test d'écriture/compilation/téléchargement/exécution dure environ 30 secondes.

2
Tod

De nombreux processeurs intégrés sont disponibles sur les cartes d'évaluation, donc même si vous ne disposez pas de vos vrais périphériques d'E/S, vous pouvez souvent exécuter une grande partie de vos algorithmes et de votre logique sur l'un de ces types de choses, souvent avec un débogage matériel disponible via jtag. Et les tests "unitaires" concernent généralement davantage votre logique que vos E/S de toute façon. Le problème est généralement de récupérer vos artefacts de test out de l'un de ces environnements.

0
JustJeff

Divisez le code entre dépendant de l'appareil et indépendant de l'appareil. Le code indépendant peut être testé à l'unité sans trop de douleur. Le code dépendant devra simplement être testé manuellement jusqu'à ce que vous disposiez d'une interface de communication fluide.

Si vous êtes écrit l'interface de communication, je suis désolé.

0
Paul Nathan