208 votes

Comment puis-je tester unitairement le code Arduino ?

J'aimerais pouvoir tester mon code Arduino à l'unité. L'idéal serait de pouvoir exécuter les tests sans avoir à télécharger le code sur l'Arduino. Quels outils ou bibliothèques peuvent m'y aider ?

Il existe un Émulateur Arduino en cours de développement qui pourrait être utile, mais qui ne semble pas encore prêt à être utilisé.

Studio AVR d'Atmel contient un simulateur de puce qui pourrait être utile, mais je ne vois pas comment l'utiliser en conjonction avec l'IDE Arduino.

1 votes

Il existe un autre fil de discussion sur cette question datant de 2011 à l'adresse suivante arduino.cc/forum/index.php?action=printpage;topic=54356.0

1 votes

Merci @Jakob. Un simulateur Arduino référencé dans ce fil (avec d'autres liens potentiellement utiles en bas de page) : arduino.com.au/Simulateur-pour-Arduino.html

6 votes

Malheureusement, c'est seulement pour Windows, j'aimerais voir un moyen de compiler et d'exécuter simplement le code Arduino à partir de la ligne de commande sans aucune dépendance matérielle ou de source fermée.

153voto

Iron Savior Points 1100

Ne pas exécuter les tests unitaires sur le dispositif Arduino ou l'émulateur

Les arguments contre les tests basés sur les microcontrôleurs Dispositif/Emulateur/Sim

Il y a beaucoup de discussions sur ce qu'est un test unitaire m pas vraiment essayer d'argumenter à ce sujet ici. Ce billet est pas vous dire d'éviter tous tests pratiques sur votre objectif ultime matériel. J'essaie d'insister sur le fait qu'il est important d'optimiser vos activités de cycle de rétroaction du développement en éliminant le matériel cible de votre système d'exploitation. de vos tests les plus banals et les plus fréquents. Les unités testées sont supposées sont supposées être beaucoup plus petites que l'ensemble du projet.

L'objectif des tests unitaires est de tester la qualité de votre propre code. En règle générale, les tests unitaires ne doivent jamais tester la fonctionnalité de facteurs sur lesquels vous n'avez aucun contrôle.

Pensez-y de la manière suivante : Même si vous deviez tester la fonctionnalité de la bibliothèque Arduino, du microcontrôleur ou d'un émulateur, il n'est pas possible de tester la fonctionnalité de la bibliothèque Arduino ou du microcontrôleur. absolument impossible que les résultats de ces tests vous renseignent sur la qualité de votre propre travail. Il est donc beaucoup plus utile et efficace d'écrire des tests unitaires qui ne s'exécutent pas sur l'appareil cible (ou l'émulateur).

Les tests fréquents sur le matériel cible ont un cycle douloureusement lent :

  1. Ajustez votre code
  2. Compilation et téléchargement vers le dispositif Arduino
  3. Observer le comportement et deviner si votre le code fait ce que vous attendez
  4. Répéter

L'étape 3 est particulièrement pénible si vous souhaitez obtenir des messages de diagnostic via le port série mais que votre projet lui-même doit utiliser le seul port série matériel de votre Arduino. Si vous pensiez que la bibliothèque SoftwareSerial pourrait vous aider, vous devez savoir que cela risque de perturber toute fonctionnalité nécessitant une synchronisation précise, comme la génération d'autres signaux en même temps. Ce problème m'est arrivé.

Encore une fois, si vous testez votre esquisse à l'aide d'un émulateur et que vos routines critiques fonctionnent parfaitement jusqu'à ce que vous les téléchargiez sur l'Arduino réel, la seule leçon que vous en tirerez est que l'émulateur est défectueux - et le fait de savoir cela révèle encore une fois que l'émulateur est défectueux. rien sur la qualité des votre propre travail.

S'il est absurde de tester sur l'appareil ou l'émulateur, que faire ? devrait Je le fais ?

Vous utilisez probablement un ordinateur pour travailler sur votre projet Arduino. Cet ordinateur est plusieurs fois plus rapide que le microcontrôleur. Écrivez les tests pour construire et fonctionner sur votre ordinateur .

Rappelez-vous que le comportement de la bibliothèque Arduino et du microcontrôleur doit être le suivant supposer qu'ils sont corrects ou, au moins, qu'ils sont de manière cohérente incorrect .

Lorsque vos tests produisent des résultats contraires à vos attentes, il est probable que le code testé présente une faille. Si les résultats de vos tests correspondent à vos attentes, mais que le programme ne se comporte pas correctement lorsque vous le téléchargez sur l'Arduino, alors vous savez que vos tests étaient basés sur des hypothèses incorrectes et que vous avez probablement un test défectueux. Dans un cas comme dans l'autre, vous aurez obtenu de réelles indications sur les prochaines modifications à apporter à votre code. La qualité de votre retour d'information est améliorée de " quelque chose est cassé" à "cette code spécifique est cassé" .

Comment construire et exécuter des tests sur votre PC

La première chose à faire est de Identifier les objectifs des tests . Réfléchissez aux parties de la votre propre code que vous voulez tester et veillez à construire votre programme de manière à ce que vous puissiez le tester. isoler des parties distinctes pour les tests.

Si les pièces que vous souhaitez tester font appel à des fonctions Arduino, vous devrez fournir des maquettes de remplacement dans votre programme de test. C'est beaucoup moins compliqué qu'il n'y paraît. Vos maquettes n'ont pas besoin de faire quoi que ce soit d'autre que de fournir des entrées et sorties prévisibles pour vos tests.

Tout le code que vous souhaitez tester doit se trouver dans des fichiers sources autres que l'esquisse .pde. Ne vous inquiétez pas, votre esquisse se compilera toujours même avec du code source en dehors de l'esquisse. En fin de compte, seul le point d'entrée normal de votre programme doit être défini dans le fichier d'esquisse.

Il ne reste plus qu'à écrire les tests réels et à les compiler à l'aide de votre compilateur C++ préféré ! La meilleure façon d'illustrer ce point est sans doute de le faire à l'aide d'un exemple concret.

Un exemple concret

L'un de mes projets favoris a trouvé aquí propose quelques tests simples qui s'exécutent sur le PC. Pour cette soumission de réponse, je vais simplement expliquer comment j'ai modélisé certaines fonctions de la bibliothèque Arduino et les tests que j'ai écrits pour tester ces modélisations. Ceci n'est pas contraire à ce que j'ai dit précédemment sur le fait de ne pas tester le code d'autrui car c'est moi qui ai écrit les maquettes. Je voulais être certain que mes maquettes étaient correctes.

Source de mock_arduino.cpp, qui contient du code dupliquant certaines fonctionnalités de support fournies par la bibliothèque Arduino :

#include <sys/timeb.h>
#include "mock_arduino.h"

timeb t_start;
unsigned long millis() {
  timeb t_now;
  ftime(&t_now);
  return (t_now.time  - t_start.time) * 1000 + (t_now.millitm - t_start.millitm);
}

void delay( unsigned long ms ) {
  unsigned long start = millis();
  while(millis() - start < ms){}
}

void initialize_mock_arduino() {
  ftime(&t_start);
}

J'utilise la maquette suivante pour produire une sortie lisible lorsque mon code écrit des données binaires sur le périphérique série matériel.

fake_serial.h

#include <iostream>

class FakeSerial {
public:
  void begin(unsigned long);
  void end();
  size_t write(const unsigned char*, size_t);
};

extern FakeSerial Serial;

fake_serial.cpp

#include <cstring>
#include <iostream>
#include <iomanip>

#include "fake_serial.h"

void FakeSerial::begin(unsigned long speed) {
  return;
}

void FakeSerial::end() {
  return;
}

size_t FakeSerial::write( const unsigned char buf[], size_t size ) {
  using namespace std;
  ios_base::fmtflags oldFlags = cout.flags();
  streamsize oldPrec = cout.precision();
  char oldFill = cout.fill();

  cout << "Serial::write: ";
  cout << internal << setfill('0');

  for( unsigned int i = 0; i < size; i++ ){
    cout << setw(2) << hex << (unsigned int)buf[i] << " ";
  }
  cout << endl;

  cout.flags(oldFlags);
  cout.precision(oldPrec);
  cout.fill(oldFill);

  return size;
}

FakeSerial Serial;

et enfin, le programme d'essai proprement dit :

#include "mock_arduino.h"

using namespace std;

void millis_test() {
  unsigned long start = millis();
  cout << "millis() test start: " << start << endl;
  while( millis() - start < 10000 ) {
    cout << millis() << endl;
    sleep(1);
  }
  unsigned long end = millis();
  cout << "End of test - duration: " << end - start << "ms" << endl;
}

void delay_test() {
  unsigned long start = millis();
  cout << "delay() test start: " << start << endl;
  while( millis() - start < 10000 ) {
    cout << millis() << endl;
    delay(250);
  }
  unsigned long end = millis();
  cout << "End of test - duration: " << end - start << "ms" << endl;
}

void run_tests() {
  millis_test();
  delay_test();
}

int main(int argc, char **argv){
  initialize_mock_arduino();
  run_tests();
}

Ce billet est déjà assez long, veuillez donc vous référer à mon projet sur GitHub pour voir d'autres cas de test en action. Je garde mes travaux en cours dans d'autres branches que master, donc vérifiez ces branches pour des tests supplémentaires, aussi.

J'ai choisi d'écrire mes propres routines de test légères, mais des cadres de test unitaires plus robustes comme CppUnit sont également disponibles.

1 votes

C'est une excellente réponse ! Merci !

0 votes

On pourrait lire "ne pas tester sur n'importe quel système". Tout dispositif réel (embarqué ou non) n'est pas pur, donc nous devrions tester uniquement via des preuves symboliques/mathématiques ? Les tests unitaires testent le code dans le contexte de choix (langage, compilateur, drapeaux, bibliothèques), qui ont tous un effet sur la correction. Voyez comment "J'ai développé et testé un code correct, mais pas pour le compilateur et la plateforme que nous avons choisis pour le projet" s'envole avec votre chef de projet avant de devenir trop puriste sur les tests. ArduinoUnit supporte les tests unitaires sur les Arduinos, mais ils doivent être exécutés ou simulés quelque part.

7 votes

@WarrenMacEvoy Encore une fois, je pense que vous avez pris mon conseil et en avez fait quelque chose qu'il n'est pas. Vous devriez certainement tester votre code dans son environnement réel à un moment donné. Mon argument est que vous ne devriez pas le faire tous les jours et que vous ne devriez certainement pas l'appeler un test unitaire.

66voto

Matthew Murdoch Points 11530

En l'absence de tout cadre de test unitaire préexistant pour Arduino, j'ai créé ArduinoUnité . Voici un simple sketch Arduino démontrant son utilisation :

#include <ArduinoUnit.h>

// Create test suite
TestSuite suite;

void setup() {
    Serial.begin(9600);    
}

// Create a test called 'addition' in the test suite
test(addition) {
    assertEquals(3, 1 + 2);
}

void loop() {
    // Run test suite, printing results to the serial port
    suite.run();
}

20 votes

Les tests semblent s'exécuter uniquement sur l'arduino, vous ne pouvez donc pas les exécuter automatiquement sur votre machine de développement. L'idée de base des tests unitaires est de les exécuter automatiquement, donc la conception actuelle semble être plus un outil de débogage mais pas un véritable cadre de test unitaire.

1 votes

Vous avez raison. Pour pouvoir les faire fonctionner sur un PC, il faudrait en plus un émulateur Arduino ou AVR. Il n'y a pas de véritable couche d'abstraction matérielle dans les bibliothèques Arduino (pour l'instant) et les émulateurs AVR étaient tous en cours de développement lorsque j'ai regardé. Si les choses ont évolué maintenant, alors en principe cela pourrait être fait.

0 votes

@MatthewMurdoch Je pense que c'est une excellente idée. Je sais que je serais intéressé par quelque chose comme ça une fois qu'un émulateur AVR correct sera sorti.

23voto

David Sykes Points 9683

J'ai beaucoup de succès dans les tests unitaires de mon code PIC en faisant abstraction de l'accès matériel et en le simulant dans mes tests.

Par exemple, j'ai abstrait PORTA avec

#define SetPortA(v) {PORTA = v;}

SetPortA peut alors être facilement simulé, sans ajouter de code supplémentaire dans la version PIC.

Une fois que l'abstraction matérielle a été testée pendant un certain temps, je constate généralement que le code passe du banc d'essai au PIC et fonctionne du premier coup.

Mise à jour :

J'utilise un filon #include pour le code unitaire, #incluant le code unitaire dans un fichier C++ pour le banc d'essai, et un fichier C pour le code cible.

Par exemple, je veux multiplexer quatre écrans de 7 segments, un port pilotant les segments et un second sélectionnant l'écran. Le code d'affichage s'interface avec les écrans via SetSegmentData(char) y SetDisplay(char) . Je peux les simuler dans mon banc d'essai C++ et vérifier que j'obtiens les données que j'attends. Pour la cible, j'utilise #define afin d'obtenir une affectation directe sans la surcharge d'un appel de fonction.

#define SetSegmentData(x) {PORTA = x;}

0 votes

Je vois en principe comment je peux utiliser le préprocesseur "seam" pour les tests unitaires. Cependant, je ne suis pas sûr de pouvoir le faire sans avoir un émulateur sur lequel exécuter les tests ou un compilateur compatible avr-gcc qui produit (dans mon cas) des binaires Windows...

0 votes

Merci pour la mise à jour. Exécutez-vous les tests unitaires sur le PIC ou sur votre PC ?

0 votes

Les tests unitaires sont exécutés sur un Mac en utilisant Xcode. Pour les exécuter sur le Pic, il faudrait probablement un émulateur quelconque. L'abstraire pour qu'il fonctionne sur le Mac rend le changement de processeur beaucoup plus facile.

15voto

Gonzo Points 179

Il semble que emulino ferait parfaitement l'affaire.

Emulino est un émulateur pour la plateforme Arduino par Greg Hewgill. ( Source : )

Dépôt GitHub

12voto

Gonzo Points 179

simavr est un AVR simulateur en utilisant avr-gcc.

Il supporte déjà quelques microcontrôleurs ATTiny et ATMega, et - selon l'auteur - il est facile d'en ajouter d'autres.

Dans les exemples se trouve simduino, un émulateur Arduino. Il supporte l'exécution du bootloader Arduino et peut être programmé avec avrdude par le biais de Socat (a modifié Netcat ).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X