meilleure pratique lors des tests unitaires pour le développement intégré


45

Je recherche des stratégies de meilleures pratiques pour le code de test unitaire écrit pour un système embarqué. Par système embarqué, j'entends des codes tels que des pilotes de périphérique, des gestionnaires d'ISR, etc., des éléments assez proches du métal.

La plupart des tests unitaires ne sont pas possibles sans le tester sur le matériel à l'aide d'un ICE. Parfois, l'unité intégrée doit également être connectée à un autre stimulus, tel qu'un interrupteur mécanique, un moteur pas à pas et des ampoules. Cela se produit généralement de manière manuelle, l'automatisation serait géniale mais difficile et coûteuse à réaliser.

Mise à jour

Je suis tombé sur un framework de test C qui semble assez efficace pour tester des projets intégrés. Il utilise les idées de matériel moqueur. Découvrez Unity , CMock et éventuellement Ceedling .

Mise à jour 06juil2016

Entré à travers cmocka - semble être plus activement travaillé.


1
Dans des circonstances similaires, nous avons opté pour Cmocka
Mawg le

J'ai écrit un tutoriel très complet sur le sujet: Test unitaire des applications C intégrées avec Ceedling
Dmitry Frank

Réponses:


28

Je ferais abstraction des dépendances matérielles le plus tôt possible et construirais le système sur des faisceaux de test / émulation logicielle, permettant toutes sortes de structures de test. Souvent, mon ordinateur de développement était utilisé pour tester jusqu'à 95% ou plus du système complet. Le coût de la surcharge supplémentaire (une autre couche d'abstraction) a été facilement récupéré par le code de nettoyage généré à la suite de cette abstraction.

Le test des parties véritablement baremetales d'un système embarqué est généralement une application distincte (test unitaire?) Qui enfonce le micrologiciel bien au-delà de ce que les applications peuvent même espérer atteindre. L'automatisation peut être réalisée - à un coût, mais n'est pas typique.

À moins que vous n’ayez le budget nécessaire pour construire un harnais de matériel de test unitaire, y compris ICE complet. Cela convient parfaitement, car les tests fonctionnels sont généralement petits.


Ceci combiné avec la réponse de Jonathan Cline Ieeee est une stratégie réussie. Utilisez l'abstraction pour rendre le code testable et utilisez un simple framework de test pour tester les bits non abstraites sur le matériel réel. J'ai personnellement vu ce travail avec plusieurs plates-formes.
Tim Williscroft

3
Chaque produit que nous fabriquons possède une couche d'abstraction matérielle avec implémentation de pilotes pour la plate-forme cible et le PC. Cela nous permet d’effectuer facilement des tests unitaires. Autres avantages: nous pouvons également exécuter des tests système rapides et développer la plupart des logiciels sans aucun matériel (car ils seront disponibles ultérieurement).
MaR

15

Un outil nécessaire pour développer est un injecteur de signal. Le système intégré disposera d’un moyen d’interfaçage avec un système hôte (généralement via un port série réservé au débogage). Utilisez cette option pour envoyer des données de test (la meilleure option est un format ASCII abrégé, de sorte qu’il soit facilement simulé par les humains).

Je suis complètement en désaccord avec cette partie de votre question: "l'automatisation serait géniale mais difficile et coûteuse à réaliser".

En utilisant TeraTerm en tant qu’injecteur de signal de port série et en écrivant des macros TeraTerm (environ 20 minutes), il existe une vaste suite de tests automatisés pouvant être exécutés sur n’importe quelle partie d’un système intégré - qu’il s’agisse de la couche de pilote, du système d’exploitation, couche 4-5, etc. TeraTerm: http://en.sourceforge.jp/projects/ttssh2/

Si le port série n'est pas disponible sur le système intégré, utilisez un outil matériel pour convertir les données du port USB / série en signaux numériques (également peu coûteux et facile à obtenir). Pendant que vous lisez ceci, j’utilise une carte à microcontrôleur à 30 $ (UBW: http://www.schmalzhaus.com/UBW32/ ) pour tester un système embarqué en vue de sa production, en injectant un stimulus via des macros TeraTerm qui est envoyé via USB / série à le microcontrôleur, qui exécute un micrologiciel modifié, qui exploite les entrées numériques et surveille les sorties numériques du système intégré cible. Parallèlement, nous avons développé un script python (utilisant pyserial et pexpect) pour automatiser l’injection et la validation des données. Rien de tout cela n'est dur et rien n'est cher. D'après mon expérience, les gestionnaires dépensent beaucoup (par exemple 30 000 dollars en équipement de test) lorsque l'équipe de test est inexpérimentée et ne peut concevoir ces solutions faciles. Malheureusement, l'équipement grand public à usage général n'inclut pas souvent les cas de test. qui attrape le pire cas / timing du système cible. La méthode peu coûteuse est donc préférable pour la couverture du test. Croyez-le ou non.


1
Eh bien, j’ai fait cette déclaration coûteuse alors que je travaillais dans l’industrie automobile. Tout doit être déterministe, reproductible et nécessite généralement deux ou trois ingénieurs pour se développer. De même, lorsque davantage d'éléments sont utilisés dans la chaîne de test, la maintenance devient également un problème. Merci de nous avoir informé sur le programme UBW, cela semble être une bonne option.
Tehnyit

2
Ne me lancez pas sur LabView… ce sont des choses horribles en général.
Jonathan Cline IEEE

1
Nos ingénieurs de test adorent LabView, je ne le comprends pas tout à fait.
Tehnyit

C'est assez proche de ce que je fais pour divers tests, seulement j'utilise Python et leurs bibliothèques de séries. Je pourrais ensuite brancher mes tests de bas niveau dans les testeurs unitaires de Python avec quelque chose comme Flask / Qt pour offrir également une interface frontale facile à utiliser.
radix07

5

C'est un problème très difficile.

En fait, j'ai conçu un harnais de tests unitaires pour un système embarqué, qui permettrait de simuler des interruptions / événements matériels et de contrôler la synchronisation de l'exécution (afin de couvrir tous les interconnexions possibles dues à la simultanéité), Les programmeurs ont plus de deux ans pour le mettre en œuvre et le mettre au travail. Ce projet est un développement exclusif, mais un projet similaire (de conception plus simple) est disponible ici .

Alors oui, l'automatisation serait géniale. Oui, c'est très difficile et coûteux à réaliser. Oui, parfois il faut faire ça. Rarement cependant, dans mon expérience dans la plupart des cas, il est plus rapide et moins coûteux d’utiliser les moteurs pas à pas et les ampoules électriques et de le faire fonctionner manuellement.


J'ai constaté que l'unité est sujette aux erreurs manuellement, généralement en générant le stimulus ou en mesurant les résultats. Cela est particulièrement vrai si le test unitaire est compliqué. Si vous devez refaire le test unitaire, il est encore plus sujet aux erreurs.
Tehnyit

@tehnyit - oui, c'est la raison pour laquelle nous avons décidé de développer le système d'automatisation. Parfois, les choses ne peuvent pas être faites manuellement, mais le test unitaire doit être complet et couvrir les problèmes de timing. Dans ce cas, vous n’avez pas beaucoup de choix, mais l’automatisation à ce niveau est une opération très coûteuse.
Littleadv

4

Edit: ma réponse est proche de celle de mattnz, je pense ...


Je souhaite relier ce problème à d'autres, tous les tests dépendant de quelque chose d'extérieur à votre code (comme une horloge système, un système de fichiers persistant ou une base de données, contacter un service Web externe ...). Je suggère la même politique pour tous, isolez les deux niveaux en deux couches de code.

Test d'une seule opération externe

Vous voudrez peut-être tester physiquement chaque opération. Vérifiez que l'horloge système donne l'heure correcte, vérifiez qu'un fichier se souvient réellement de ce qui a été écrit, vérifiez qu'un périphérique ne reçoit qu'une seule opération ...

Ces tests:

  • devrait être aussi simple que possible: aucun algorithme, aucune condition ou boucle
  • peut dépendre de l’ordre et de la machine: vous devez donc suivre un ordre strict et répéter chaque matériel
  • sont généralement stables au cours de votre projet, vous n’avez donc pas besoin de les exécuter aussi souvent
  • donc les exécuter manuellement est une option; l'automatisation est encore meilleure, sinon trop complexe
  • Notez que ce qui est testé n'est pas votre code , c'est un outil dont votre code a besoin ... Donc, le tester peut être facultatif pour vous, cela peut avoir été fait par une autre équipe ...

Tester la logique (code, algorithme) qui relie les opérations externes

En disposant d'une couche de code pour effectuer les opérations externes réelles, en les cachant derrière une interface que vous pouvez facilement simuler, votre logique n'est plus dépendante des périphériques physiques réels ...

Vous pouvez simplement tester, comme tout projet classique, vous n'êtes plus dans un code difficile à tester .


3

Les simulateurs de CPU intégrés peuvent généralement être programmés pour simuler également du matériel. Toutes les technologies de virtualisation autres que Xen le font. Mais vous devez écrire du code prétendant avoir certains registres à une adresse physique ou, sur x86, une adresse sur le bus d’E / S, puis vous devez répondre aux lectures et écritures sur ces adresses comme si votre logiciel était physique. puce dont les registres de contrôle et d'état étaient en cours d'accès.

Si vous voulez faire cela, je suggérerais de modifier QEMU. Mais ce ne serait pas facile. Ce type de tâche n’est généralement effectué que lorsque vous concevez une puce personnalisée avec un microcontrôleur et quelques autres cœurs pour vos E / S.

Le système de développement vendu par ARM Holdings répond à cela et est probablement plus facile à utiliser que le piratage informatique sur QEMU, mais il est très coûteux.

Il existe plusieurs émulateurs ARM Open Source qui exécutent une seule sous-routine, qui peut elle-même appeler d'autres sous-routines, que vous pouvez utiliser pour le débogage en optimisant les performances des sous-routines ne dépendant pas d'un accès matériel. J'ai utilisé l'un de ces logiciels avec un grand succès pour optimiser un crypteur AES pour ARM7TDMI.

Vous pouvez écrire un faisceau de test unitaire simple en C ou C ++, y associer la classe ou le sous-programme testé, puis l'exécuter dans le simulateur.

Je réfléchis à un problème similaire depuis des années: comment tester un peu le code du noyau Linux ou Mac OS X. Cela devrait être possible, mais je n'ai jamais vraiment essayé. L'une d'elles est peut-être de construire un noyau complet plutôt que de tester votre code de manière isolée, le framework de test unitaire étant directement lié à votre noyau. Vous lanceriez ensuite les tests unitaires à partir d'une sorte d'interface externe.

Peut-être serait-il plus productif d'utiliser un outil de couverture de code, puis de tester votre micrologiciel comme un package complet via son interface externe. L'outil de couverture trouverait des chemins de code qui n'avaient pas encore été testés. Vous pourrez alors ajouter des tests externes supplémentaires pour tenter d'obtenir une plus grande couverture.


3

Comme avec le TDD non intégré, les objets fantaisie sont définitivement votre ami.

Conservez une interface propre et simple avec votre matériel sous-jacent, de sorte que tout ce qui se trouve au-dessus du niveau le plus bas puisse être simulé et que vous ayez beaucoup plus de facilité. Si vous concevez votre application intégrée avec à l'esprit la testabilité, les tests se dérouleront toujours de manière beaucoup plus fluide. .

De plus, le fait que vous ne puissiez peut-être pas tester en ligne assez tard dans le projet ne signifie pas que vous ne devriez pas non plus préparer une suite de tests en ligne.

Celles-ci ne devraient (initialement) que tester les bits qui ne pouvaient pas être testés hors ligne. Bien sûr, ce n'est pas TDD (puisque vous créez les tests à l'avance), mais votre développement TDD hors ligne devrait vous donner une bonne idée de ce à quoi votre interface matérielle doit ressembler et, par conséquent, des tests en ligne que vous devez effectuer.

En outre, si le développement en ligne coûte beaucoup plus cher que le développement hors connexion (comme c'est le cas là où je travaille), vous économiserez ainsi beaucoup de temps en ligne grâce à un ensemble de tests bien compris.


+1 pour amener des objets fantaisie sur la plaque, @mark. Le seul problème est que la précision des objets fantaisie, ce qui signifie que la compréhension de l'objet à simuler doit être assez profonde. C'est une bonne chose car cela oblige le développeur à comprendre le comportement des objets externes avec lesquels il s'interface.
Tehnyit

1

Dans le développement intégré, vous effectuez souvent des analyses des limites pour vérifier le fonctionnement complet de l'application (matériel compris). Voir aussi JTAG pour le débogage du système.

Le test de routines logicielles pures sans lien avec le matériel peut être effectué à l'aide d'un framework de test d'unité C standard tel que Check . Mais méfiez-vous des limitations de mémoire (notamment stackspace, etc. sur de petits périphériques). Connaissez vos contrats! Vous pouvez également essayer d'extraire les routines logicielles du matériel pour obtenir une couverture de test plus étendue, mais cela est généralement coûteux en termes de performances sur des périphériques intégrés tels que de petits PIC ou AVR. Cependant, vous pouvez simuler des ports matériels pour obtenir une plus grande couverture (et bien sûr, vous pouvez également tester cette simulacre).

Vous pouvez également essayer d'utiliser des émulateurs pour les simluateurs de puces ou de circuits, mais ces types d'outils sont coûteux (en particulier combinés) et compliqués.


En accord avec le scan de périmètre et JTAG, mais, en raison de la conception du matériel, il n’est pas toujours possible ni disponible.
Tehnyit
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.