Comment puis-je tester le code Arduino?
J'aimerais pouvoir tester mon code Arduino. Idéalement, je serais en mesure d'exécuter des tests sans avoir à télécharger le code sur L'Arduino. Quels outils ou bibliothèques peuvent m'aider avec cela?
Il y a un émulateur Arduino en développement {[4] } qui pourrait être utile, mais il ne semble pas encore prêt à l'emploi.
AVR Studio D'Atmel contient un simulateur de puce qui pourrait être utile, mais je ne vois pas comment je l'utiliserais en conjonction avec L'Arduino IDE.
18 réponses
N'exécutez pas de Tests unitaires sur le périphérique Arduino ou L'émulateur
Le cas contre les tests basés sur un microcontrôleur/émulateur/Sim
Le but des tests unitaires est de tester la qualité de votre propre code. Les tests unitaires devraient Ne jamais tester la fonctionnalité de facteurs hors de votre contrôle.
Pensez-y de cette façon: même si vous deviez tester la fonctionnalité de la bibliothèque Arduino, le matériel du microcontrôleur, ou un émulateur, il est absolument impossible pour de tels résultats de test pour vous dire quoi que ce soit sur la qualité de votre propre travail. Par conséquent, il n'y a absolument aucune valeur en écrivant des tests unitaires qui s'exécutent sur le périphérique (ou l'émulateur).
Peu importe si vous envisagez d'exécuter des tests sur l'appareil ou un émulateur, vous vous faites toujours répéter un processus brutalement lent de:
- modifier votre code
- compiler et télécharger sur le périphérique Arduino
- Observez le comportement et faites des suppositions quant à savoir si ou non il est en marche.
- répéter
L'Étape 3 est particulièrement désagréable si vous prévoyez d'obtenir des messages de diagnostic via le port série, mais 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 un timing précis, comme la génération d'autres signaux en même temps. Ce problème est arrivé à je.
Encore une fois, si vous deviez tester votre croquis en utilisant un émulateur et que vos routines critiques fonctionnaient parfaitement jusqu'à ce que vous ayez téléchargé sur l'Arduino, alors la seule leçon que vous allez apprendre est que l'émulateur est défectueux-et sachant cela ne révèle toujours rien rien sur la qualité de votre propre travail!
S'il est stupide de tester sur l'appareil ou l'émulateur, que devrais-je faire?
Vous utilisez probablement un ordinateur pour travailler sur votre projet Arduino. Que l'ordinateur est littéralement milliers de fois plus rapide que le microcontrôleur. Écrivez les tests à construire et exécutez sur votre ordinateur .
Rappelez-vous que le comportement de la bibliothèque Arduino et du microcontrôleur doit être supposé correct ou au moins systématiquement incorrect.
Lorsque vos tests produisent des résultats contrairement à vos attentes, vous avez probablement un défaut dans votre code qui a été testé. Si votre résultat de test correspond à votre attentes, mais 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 vous avez probablement un test défectueux. Dans les deux cas, vous aurez reçu de vraies idées sur ce que vos prochains changements de code devraient être.
Comment Construire et exécuter des Tests sur votre PC
La première chose que vous devez faire est de identifier vos objectifs de test. Pensez à quelles parties de votre propre code vous voulez tester et puis assurez-vous de construire votre programme de telle façon que vous pouvez isoler les parties discrètes pour les tests.
Si les pièces que vous souhaitez tester appellent des fonctions Arduino, vous devrez fournir des remplacements de maquette dans votre programme de test. C'est beaucoup moins de travail qu'il n'y paraît. Vos maquettes n'ont pas à faire autre chose que de fournir une entrée et une sortie prévisibles pour vos tests.
Tout code que vous avez l'intention de tester doit exister dans les fichiers source autres que l' .de la pde esquisse. Ne vous inquiétez pas, votre esquisse compilera toujours même avec du code source en dehors de l'esquisse. Lorsque vous y arrivez vraiment, un peu plus que 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 puis à les compiler en utilisant votre compilateur C++ préféré! Ceci est probablement mieux illustré par un exemple du monde réel.
Un exemple de travail réel
Un de mes projets animaux trouvé ici a quelques tests simples qui s'exécutent sur le PC. Pour cette soumission de réponse, je vais juste passer en revue la façon dont j'ai moqué certaines fonctions de la bibliothèque Arduino et les tests que j'ai écrits pour tester ces maquettes. Ce n'est pas contraire à ce que j'ai dit avant de ne pas tester le code des autres parce que 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 qui duplique certaines fonctionnalités de support fourni 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.rpc
#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 de test réel:
#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 post est 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 des branches autres que master, alors 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 frameworks de tests unitaires plus robustes comme CppUnit sont également disponibles.
En l'absence de frameworks de tests unitaires préexistants pour Arduino, j'ai créé ArduinoUnit . Voici un croquis Arduino simple 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();
}
J'ai un succès considérable en testant mon code PIC en abstrayant l'accès matériel et en le moquant dans mes tests.
Par exemple, j'abstraite PORTA avec
#define SetPortA(v) {PORTA = v;}
Ensuite, SetPortA peut facilement être moqué, sans ajouter de code de surcharge dans la version PIC.
Une fois que l'abstraction matérielle a été testée un certain temps, je trouve rapidement que le code passe généralement du banc d'essai au PIC et fonctionne pour la première fois.
Mise à Jour:
J'utilise une couture # include pour le code d'unité, #, y compris l'unité de code dans un fichier C++ pour le banc d'essai, et un fichier C pour le code cible.
A titre d'exemple, je veux Multiplexer quatre affichages à 7 segments, un port conduisant les segments et un second sélectionnant l'affichage. Le code d'affichage s'interface avec les affichages via SetSegmentData(char)
et SetDisplay(char)
. Je peux me moquer de ceux-ci dans mon banc de test 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;}
Simavr est un simulateur AVR utilisant avr-gcc.
Il supporte déjà quelques microcontrôleurs ATTiny et ATMega, et-selon l'auteur-il est facile d'en ajouter un peu plus.
Dans les exemples se trouve simduino, un émulateur Arduino. Il prend en charge l'exécution du chargeur de démarrage Arduino et peut être programmé avec avrdude via Socat (Un netcat modifié).
Vous pouvez tester l'unité en Python avec mon projet, PySimAVR . Arscons est utilisé pour la construction et simavr pour la simulation.
Exemple:
from pysimavr.sim import ArduinoSim
def test_atmega88():
mcu = 'atmega88'
snippet = 'Serial.print("hello");'
output = ArduinoSim(snippet=snippet, mcu=mcu, timespan=0.01).get_serial()
assert output == 'hello'
Test de démarrage:
$ nosetests pysimavr/examples/test_example.py
pysimavr.examples.test_example.test_atmega88 ... ok
Je ne suis au courant d'aucune plate-forme qui peut tester le code Arduino.
Cependant, il y a le Fritzing plate-forme, que vous pouvez utiliser pour modéliser le matériel et plus tard sur les diagrammes de PCB d'exportation et d'autres choses.
Vaut la peine d'être vérifié.
Nous utilisons des cartes Arduino pour l'acquisition de données dans une grande expérience scientifique. Par la suite, nous devons prendre en charge plusieurs cartes Arduino avec différentes implémentations. J'ai écrit des utilitaires Python pour charger dynamiquement des images hexadécimales Arduino pendant les tests unitaires. Le code trouvé sur le lien ci-dessous prend en charge Windows et Mac OS X via un fichier de configuration. Pour savoir où vos images hexadécimales sont placées par L'IDE Arduino, appuyez sur la touche Maj avant d'appuyer sur le bouton build (play). Frapper la touche maj enfoncée tout en frapper upload pour savoir où se trouve votre avrdude (utilitaire de téléchargement en ligne de commande) sur votre système / version D'Arduino. Vous pouvez également consulter les fichiers de configuration inclus et utiliser votre emplacement d'installation (actuellement sur Arduino 0020).
Ce programme permet l'exécution automatisée de plusieurs tests unitaires Arduino. Le processus de test est démarré sur le PC, mais les tests s'exécutent sur le matériel Arduino réel. Un ensemble de tests unitaires est généralement utilisé pour tester une bibliothèque Arduino. (ceci
Forum Arduino: http://arduino.cc/forum/index.php?topic=140027.0
Page du projet GitHub: http://jeroendoggen.github.com/Arduino-TestSuite
Page dans L'Index du paquet Python: http://pypi.python.org/pypi/arduino_testsuite
Les tests unitaires sont écrits avec la "bibliothèque de tests unitaires Arduino": http://code.google.com/p/arduinounit
Les étapes suivantes sont effectuées pour chaque ensemble de tests unitaires:
- lisez le fichier de configuration pour savoir quels tests exécuter
- le script compile et télécharge une esquisse Arduino contenant le code de test unitaire.
- Les tests unitaires sont exécutés sur l'Arduino bord.
- les résultats du test sont imprimés sur le port série et analysés par le script Python.
- le script démarre le test suivant, en répétant les étapes ci-dessus pour tous les tests demandés dans le fichier de configuration.
- le script affiche un résumé montrant un aperçu de tous les tests échoués/réussis dans la suite de test complète.
J'utilise Searduino lors de l'écriture de code Arduino. Searduino est un simulateur Arduino et un environnement de développement (Makefiles, code C...) qui le rend facile à pirater en C / C++ en utilisant votre éditeur préféré. Vous pouvez importer des croquis Arduino et les exécuter dans le simulateur.
Capture d'écran de Searduino 0.8: http://searduino.files.wordpress.com/2014/01/jearduino-0-8.png
Searduino 0.9 sera publié et une vidéo sera enregistrée dès que les derniers tests sont faire .... dans un jour ou deux.
Tester sur le simulateur ne doit pas être considéré comme de vrais tests, mais cela m'a certainement beaucoup aidé à trouver des erreurs stupides/logiques (oublier de faire pinMode(xx, OUTPUT)
, etc.).
BTW: je suis l'une des personnes qui développent Searduino.
Gardez le code spécifique au matériel séparé ou abstrait du reste afin que vous puissiez tester et déboguer ce plus grand "repos" sur n'importe quelle plate-forme pour laquelle vous avez de bons outils et avec laquelle vous êtes le plus familier.
Fondamentalement, essayez de construire autant de code final à partir d'autant de blocs de construction connus que possible. Le travail spécifique au matériel restant sera alors beaucoup plus facile et plus rapide. Vous pouvez le terminer en utilisant des émulateurs existants et/ou des dispositifs d'émulation par vous-même. Et puis, de bien sûr, vous aurez besoin de tester la vraie chose en quelque sorte. Selon les circonstances, cela peut ou peut ne pas être très bien automatisable (c.-à-d. qui ou quoi va appuyer sur les boutons et fournir d'autres entrées? qui ou quoi observera et interprétera divers indicateurs et extrants?).
James W. Grenning écrit de grands livres et celui-ci concerne le test unitaire du code C intégré développement piloté par les tests pour le C intégré.
Il existe un projet appelé ncore , qui fournit un noyau natif pour Arduino. Et vous permet d'écrire des tests pour le code Arduino.
De la description du projet
Le noyau natif vous permet de compiler et d'exécuter des croquis Arduino sur PC, généralement sans modification. Il fournit des versions natives de fonctions Arduino standard, et un interepreter de ligne de commande pour donner entrées à votre esquisse qui proviendraient normalement du matériel lui-même.
Aussi sur la section "de quoi ai-je besoin pour l'utiliser"
Si vous voulez construire les tests, vous aurez besoin de cxxtest http://cxxtest.tigris.org . NCORE a été testé avec cxxtest 3.10.1.
Si vous voulez tester le code à l'unité en dehors de MCU (sur le bureau), consultez libcheck: https://libcheck.github.io/check/
Je l'ai utilisé pour tester mon propre code intégré quelques fois. C'est assez solide cadre.
Je suis heureux d'annoncer (ce qui semble être) la première version stable de ruby gem appelé arduino_ci
ce que j'ai construit à cet effet. Bien qu'il soit limité à tester les bibliothèques Arduino (et non des croquis autonomes), il permet d'exécuter des tests unitaires sur Travis CI.
En supposant que vous avez Ruby et rubygems installés, ajouter cette CI à une bibliothèque est simple. Imaginons une bibliothèque très simple dans votre répertoire de bibliothèque Arduino, appelée DoSomething
. Il contient un en-tête fichier, et cette implémentation:
#include <Arduino.h>
#include "do-something.h"
int doSomething(void) {
return 4;
};
Testons-le avec arduino_ci
. Tout d'abord, vous devez ajouter un Gemfile
dans le répertoire de base de votre bibliothèque avec le contenu suivant:
source 'https://rubygems.org'
gem 'arduino_ci', '~> 0.1.7'
Ensuite, exécutez bundle install
.
Ensuite, créez un répertoire appelé test/
. (Chaque fichier .cpp
que vous placez ici sera considéré comme une suite de tests distincte). Nous allons créer un test pour l'instant, dans test/is_four.cpp
:
#include <ArduinoUnitTests.h>
#include "../do-something.h"
unittest(library_does_something)
{
assertEqual(4, doSomething());
}
unittest_main() // this is a macro for main(). just go with it.
C'est tout. Si cette syntaxe et cette structure de test assertEqual
semblent familières, c'est parce que je la bibliothèque Arduinounit de Matthew Murdoch est une bibliothèque de livres.]}
qu'il a évoqué dans sa réponse.
Maintenant, vous êtes prêt à exécuter bundle exec arduino_ci_remote.rb
, qui exécutera ces tests. Cela pourrait donner quelque chose comme ceci:
$ bundle exec arduino_ci_remote.rb
Installing library under test... ✓
Library installed at /Users/XXXXX/Documents/Arduino/libraries/DoSomething... ✓
Checking GCC version...
Using built-in specs.
COLLECT_GCC=g++-4.9
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc@4.9/4.9.4_1/libexec/gcc/x86_64-apple-darwin16. 7.0/4.9.4/lto-wrapper
Target: x86_64-apple-darwin16.7.0
Configured with: ../configure --build=x86_64-apple-darwin16.7.0 --prefix=/usr/local/Cellar/gcc@4.9/4.9.4_1 --libdir=/usr/local/Cellar/gcc@4.9/4.9.4_1/lib/gcc/4.9 --enable-languages=c,c++,objc, obj-c++,fortran --program-suffix=-4.9 --with-system-zlib --enable-libstdcxx-time=yes --enable-stage1-checking --enable-checking=release --enable-lto --enable-plugin --with-build-config=bootstrap-debug --disable-werror --with-pkgversion='Homebrew GCC 4.9.4_1' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues MAKEINFO=missing --disable-nls --enable-multilib
Thread model: posix
gcc version 4.9.4 (Homebrew GCC 4.9.4_1)
...Checking GCC version ✓
Installing board package arduino:sam... ✓
Unit testing is_four.cpp...
TAP version 13
1..1
# Subtest: library_does_something
ok 1 - assertEqual 4 == doSomething()
1..1
ok 1 - library_does_something
...Unit testing is_four.cpp ✓
Failures: 0
Exécuter le même code dans le cadre d'un travail CI sur Travis CI (par exemple pour que vous puissiez le déclencher à partir des requêtes de pull GitHub) est également simple. Ajoutez simplement ceci à votre fichier .travis.yml
:
language: ruby
script:
- bundle install
- bundle exec arduino_ci_remote.rb
Bien sûr, il y a beaucoup plus de puissance et la flexibilité de cette bibliothèque CI que je vais entrer ici. Voici quelques autres exemples:
- La DoSomething exemple bibliothèque montré ci-dessus, utilisé pour tester arduino_ci lui-même
- un exemple pratique, tester une implémentation de file d'attente
- un exemple complexe, simulant une bibliothèque qui contrôle un périphérique interactif sur une connexion SoftwareSerial dans le cadre de la bibliothèque Adafruit FONA
Utilisez Proteus VSM avec une bibliothèque Arduino pour déboguer votre code ou le tester.
C'est une bonne pratique avant d'intégrer votre code, mais assurez-vous des timings car la simulation ne fonctionne pas en temps réel car elle s'exécute sur la carte.
Essayez Autodesk Circuit simulator . Il permet de tester le code et les circuits Arduino avec de nombreux autres composants matériels.