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 :
- Ajustez votre code
- Compilation et téléchargement vers le dispositif Arduino
- Observer le comportement et deviner si votre le code fait ce que vous attendez
- 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
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.
4 votes
Une petite mise à jour, 5 ans plus tard : Simavr est toujours très actif et s'est beaucoup amélioré depuis que la question a été posée. J'ai donc pensé qu'il méritait d'être remis au goût du jour. C'est peut-être l'outil idéal pour les tests de régression, les tests basés sur des scénarios et, pourquoi pas, les tests unitaires. De cette façon, le code que vous testez est le même comme celui du matériel cible.
1 votes
Pour les projets importants, considérez un testeur matériel ; un autre MCU qui peut chronométrer et tester les réactions des boutons/interrupteurs, le temps de démarrage, la température, l'utilisation v/ma, les permutations d'options étranges, etc. Oui, c'est plus de matériel à construire, mais cela peut ajouter une couche de sécurité à la révision. Beaucoup d'appareils professionnels utilisent jtag et autres.
1 votes
Il existe désormais un Action GitHub disponible à cet effet, dont je suis l'auteur.