Quelles meilleures pratiques avez-vous utilisées dans les tests unitaires de logiciels embarqués propres aux systèmes embarqués?
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:
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.
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:
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:
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.
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 .
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).
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.
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:
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.
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.
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é.