¿Cómo puedo realizar pruebas unitarias de código Arduino?


Me gustaría poder probar mi código Arduino. Idealmente, sería capaz de ejecutar cualquier prueba sin tener que cargar el código en el Arduino. ¿Qué herramientas o bibliotecas pueden ayudarme con esto?

Hay un emulador de Arduino en desarrollo que podría ser útil, pero aún no parece estar listo para su uso.

AVR Studio de Atmel contiene un simulador de chip que podría ser útil, pero no puedo ver cómo lo usaría junto con el Arduino IDE.

Author: Peter Mortensen, 2009-04-23

18 answers

No Ejecute Pruebas Unitarias en el Dispositivo Arduino o Emulador

El caso contra el Dispositivo de microcontrolador/Emulador/Pruebas basadas en Sim

El propósito de las pruebas unitarias es probar la calidad de su propio código. Las pruebas unitarias deben nunca probar la funcionalidad de factores fuera de su control.

Piénselo de esta manera: Incluso si tuviera que probar la funcionalidad de la biblioteca Arduino, el hardware del microcontrolador o un emulador, es absolutamente imposible para que tales resultados de la prueba le digan cualquier cosa sobre la calidad de su propio trabajo. Por lo tanto, no hay absolutamente ningún valor en las pruebas unitarias de escritura que se ejecutan en el dispositivo (o emulador) en absoluto.

Independientemente de si está considerando realizar pruebas en el dispositivo o en un emulador, todavía está haciendo que repita un proceso brutalmente lento de:

  1. Modifica tu código
  2. Compilar y cargar en el dispositivo Arduino
  3. Observar el comportamiento y hacer conjeturas sobre si está funcionando o no.
  4. Repeat

El paso 3 es particularmente desagradable si espera recibir mensajes de diagnóstico a través del puerto serie, pero su proyecto en sí necesita usar el único puerto serie de hardware de su Arduino. Si estaba pensando que la biblioteca de SoftwareSerial podría ayudar, debe saber que hacerlo es probable que interrumpa cualquier funcionalidad que requiera una sincronización precisa, como generar otras señales al mismo tiempo. Este mismo problema ha sucedido a me.

Nuevamente, si probaras tu boceto usando un emulador y tus rutinas de tiempo crítico funcionaran perfectamente hasta que subieras al Arduino real, entonces la única lección que vas a aprender es que el emulador es defectuoso!y saber esto todavía revela nada acerca de la calidad de tu propio trabajo!

Si es tonto probar en el dispositivo o emulador, ¿qué debería hacer?

Probablemente estés usando una computadora para trabajar en tu proyecto Arduino. Que la computadora es literalmente miles de veces más rápida que el microcontrolador. Escriba las pruebas para compilar y ejecute en su computadora.

Recuerde, el comportamiento de la biblioteca Arduino y el microcontrolador debe ser asumido como correcto o al menos consistentemente incorrecto.

Cuando sus pruebas producen resultados contrarios a sus expectativas, entonces es probable que tenga un defecto en su código que se probó. Si la salida de la prueba coincide con expectativas, pero el programa no se comporta correctamente cuando lo carga en el Arduino, entonces usted sabe que sus pruebas se basaron en suposiciones incorrectas y es probable que tenga una prueba defectuosa. En cualquier caso, se le habrá dado información real sobre cuáles deberían ser sus próximos cambios de código.

Cómo Construir y Ejecutar Pruebas en su PC

Lo primero que debe hacer es identificar sus objetivos de prueba. Piensa en qué partes de tu propio código quieres probar y luego asegúrese de construir su programa de tal manera que pueda aislar partes discretas para probar.

Si las piezas que desea probar llaman a alguna función Arduino, deberá proporcionar reemplazos de maquetas en su programa de prueba. Esto es mucho menos trabajo de lo que parece. Sus maquetas no tienen que hacer realmente nada más que proporcionar entrada y salida predecibles para sus pruebas.

Cualquiera de su propio código que pretenda probar debe existir en los archivos fuente aparte de la.pde sketch. No te preocupes, tu sketch seguirá compilándose incluso con algún código fuente fuera del sketch. Cuando realmente se pone a ello, poco más que el punto de entrada normal de su programa debe definirse en el archivo de croquis.

¡Todo lo que queda es escribir las pruebas reales y luego compilarlas usando su compilador favorito de C++! Esto probablemente se ilustra mejor con un ejemplo del mundo real.

Un ejemplo de trabajo real

Uno de mis proyectos favoritos encontrado aquí tiene algunas pruebas simples que se ejecutan en el PC. Para este envío de respuestas, solo repasaré cómo me burlé de algunas de las funciones de la biblioteca Arduino y las pruebas que escribí para probar esas maquetas. Esto no es contrario a lo que dije antes sobre no probar el código de otras personas porque yo fui el que escribió las maquetas. Quería estar muy seguro de que mis maquetas eran correctas.

Fuente de mock_arduino.cpp, que contiene código que duplica alguna funcionalidad de soporte proporcionado por la biblioteca 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);
}

Utilizo la siguiente maqueta para producir una salida legible cuando mi código escribe datos binarios en el dispositivo serie de hardware.

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;

Y finalmente, el programa de prueba real:

#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();
}

Este post es lo suficientemente largo, así que por favor refiérase a mi proyecto en GitHub para ver más casos de prueba en acción. Mantengo mis trabajos en progreso en ramas que no sean master, así que revisa esas ramas para pruebas adicionales, también.

Elegí escribir mis propias rutinas de prueba ligeras, pero también están disponibles marcos de prueba unitarios más robustos como CppUnit.

 103
Author: Iron Savior,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-31 14:50:10

En ausencia de cualquier frameworks de pruebas unitarias preexistentes para Arduino, he creado ArduinoUnit. Aquí hay un boceto simple de Arduino que demuestra su uso:

#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();
}
 58
Author: Matthew Murdoch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-25 10:03:25

Tengo un éxito considerable probando mi código PIC abstrayendo el acceso al hardware y burlándome de él en mis pruebas.

Por ejemplo, abstract PORTA con

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

Entonces SetPortA puede ser fácilmente burlado, sin agregar código de sobrecarga en la versión PIC.

Una vez que la abstracción de hardware ha sido probada un tiempo, pronto encuentro que generalmente el código va desde el banco de pruebas hasta la foto y funciona por primera vez.

Actualización:

Utilizo un # include seam para el código de la unidad, #incluyendo el código de la unidad en un archivo C++ para el banco de pruebas, y un archivo C para el código de destino.

Como ejemplo, quiero multiplexar cuatro pantallas de 7 segmentos, un puerto que conduce los segmentos y un segundo que selecciona la pantalla. El código de visualización interactúa con las pantallas a través de SetSegmentData(char) y SetDisplay(char). Puedo burlarme de ellos en mi banco de pruebas de C++ y comprobar que obtengo los datos que espero. Para el destino utilizo #define para obtener una asignación directa sin la sobrecarga de una llamada a la función

#define SetSegmentData(x) {PORTA = x;}
 21
Author: David Sykes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-08 02:27:12

Parece que emulino haría el trabajo perfectamente.

Emulino es un emulador para la plataforma Arduino de Greg Hewgill. (Fuente )

Repositorio GitHub

 15
Author: Gonzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-07 17:18:58

Simavr es un simulador AVR usando avr-gcc.

Ya soporta algunos microcontroladores ATtiny y ATMega, y - según el autor - es fácil añadir algunos más.

En los ejemplos se encuentra simduino, un emulador de Arduino. Soporta la ejecución del gestor de arranque Arduino y se puede programar con avrdude a través de Socat (a modified Netcat ).

 11
Author: Gonzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-15 18:55:30

Puedes realizar pruebas unitarias en Python con mi proyecto, PySimAVR. Arscons se utiliza para construir y simavr para la simulación.

Ejemplo:

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'

Prueba de inicio:

$ nosetests pysimavr/examples/test_example.py
pysimavr.examples.test_example.test_atmega88 ... ok
 7
Author: ponty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-25 14:19:26

No conozco ninguna plataforma que pueda probar el código Arduino.

Sin embargo, hay la Fritzing plataforma, que puede usar para modelar el hardware y luego exportar diagramas de PCB y cosas.

Vale la pena comprobarlo.

 6
Author: Yuval Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-23 09:14:27

Estamos utilizando placas Arduino para la adquisición de datos en un gran experimento científico. Posteriormente, tenemos que soportar varias placas Arduino con diferentes implementaciones. Escribí utilidades de Python para cargar dinámicamente imágenes hexadecimales de Arduino durante las pruebas unitarias. El código que se encuentra en el siguiente enlace es compatible con Windows y Mac OS X a través de un archivo de configuración. Para averiguar dónde se colocan las imágenes hexadecimales en el IDE de Arduino, pulsa la tecla mayús antes de pulsar el botón construir (reproducir). Pulse la tecla shift mientras pulsando cargar para averiguar dónde se encuentra su avrdude (utilidad de carga de línea de comandos) en su sistema / versión de Arduino. Alternativamente, puede mirar los archivos de configuración incluidos y usar su ubicación de instalación (actualmente en Arduino 0020).

Http://github.com/toddstavish/Python-Arduino-Unit-Testing

 6
Author: toddstavish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-08 02:23:18

Este programa permite la ejecución automatizada de varias pruebas unitarias Arduino. El proceso de prueba se inicia en el PC, pero las pruebas se ejecutan en el hardware Arduino real. Un conjunto de pruebas unitarias se utiliza típicamente para probar una biblioteca Arduino. (esto

[0]} Foro de Arduino: http://arduino.cc/forum/index.php?topic=140027.0

Página del proyecto GitHub: http://jeroendoggen.github.com/Arduino-TestSuite

Página en el Índice de Paquetes de Python: http://pypi.python.org/pypi/arduino_testsuite

Las pruebas unitarias se escriben con la" Biblioteca de Pruebas Unitarias Arduino": http://code.google.com/p/arduinounit

Se realizan los siguientes pasos para cada conjunto de pruebas unitarias:

  • Lea el archivo de configuración para averiguar qué pruebas ejecutar
  • El script compila y carga un boceto de Arduino que contiene el código de pruebas unitarias.
  • Las pruebas unitarias se ejecutan en el Arduino Junta.
  • Los resultados de la prueba se imprimen sobre el puerto serie y se analizan mediante el script Python.
  • El script inicia la siguiente prueba, repitiendo los pasos anteriores para todas las pruebas que se solicitan en el archivo de configuración.
  • El script imprime un resumen que muestra una visión general de todas las pruebas fallidas/pasadas en el testsuite completo.
 6
Author: jeroendoggen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-11 12:59:39

Estoy usando Searduino al escribir código Arduino. Searduino es un simulador Arduino y un entorno de desarrollo (Makefiles, código C...) que hace que sea fácil de hackear en C / C++ utilizando su editor favorito. Puede importar bocetos de Arduino y ejecutarlos en el simulador.

Captura de pantalla de Searduino 0.8: http://searduino.files.wordpress.com/2014/01/jearduino-0-8.png

Se publicará Searduino 0.9 y se grabará un video tan pronto como se realicen las últimas pruebas Terminado.... en un día o dos.

Las pruebas en el simulador no deben considerarse pruebas reales, pero ciertamente me han ayudado mucho a encontrar errores estúpidos/lógicos (olvidarme de hacer pinMode(xx, OUTPUT), etc.).

Por cierto: Soy una de las personas que están desarrollando Searduino.

 5
Author: user3183814,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-07 17:20:13

Mantenga el código específico del hardware separado o abstraído del resto para que pueda probar y depurar ese "resto" más grande en cualquier plataforma para la que tenga buenas herramientas y con la que esté más familiarizado.

Básicamente, intenta construir la mayor cantidad de código final a partir de tantos bloques de construcción conocidos como sea posible. El resto del trabajo específico del hardware será mucho más fácil y rápido. Puede terminarlo utilizando emuladores existentes y / o emulando dispositivos por su cuenta. Y luego, de por supuesto, tendrá que probar la cosa real de alguna manera. Dependiendo de las circunstancias, eso puede o no ser muy bien automatizable (es decir, ¿quién o qué presionará los botones y proporcionará otras entradas? ¿quién o qué observará e interpretará los diversos indicadores y productos?).

 4
Author: Alexey Frunze,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-24 12:14:42

James W. Grenning escribe grandes libros y este es sobre pruebas unitarias de código C incrustado Desarrollo Basado en Pruebas para C Embebido.

 3
Author: Rafael Vega,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-25 14:17:58

Existe un proyecto llamado ncore, que proporciona núcleo nativo para Arduino. Y le permite escribir pruebas para el código Arduino.

De la descripción del proyecto

El núcleo nativo le permite compilar y ejecutar Arduino sketches en el PC, generalmente sin modificaciones. Proporciona versiones nativas de funciones estándar de Arduino, y un interepreter de línea de comandos para dar entradas a su boceto que normalmente procederían del hardware sí mismo.

También en la sección " qué necesito para usarlo "

Si desea compilar las pruebas, necesitará cxxtest desde http://cxxtest.tigris.org . NCORE ha sido probado con cxxtest 3.10.1.

 3
Author: Sudar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-11 11:37:27

Si desea realizar pruebas unitarias de código fuera de MCU( en el escritorio), consulte libcheck: https://libcheck.github.io/check /

Lo usé para probar mi propio código incrustado algunas veces. Es un marco bastante robusto.

 2
Author: ezaquarii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-19 18:10:35

Me complace anunciar (lo que parece ser) la primera versión estable de una gema ruby llamada arduino_ci que construí para este propósito. Aunque se limita a probar bibliotecas Arduino (y no bocetos independientes), permite que las pruebas unitarias se ejecuten en Travis CI.

Suponiendo que tenga Ruby y rubygems instalados, agregar este CI a una biblioteca es sencillo. Imaginemos una biblioteca muy simple en el directorio de la biblioteca de Arduino, llamada DoSomething. Contiene un encabezado archivo, y esta implementación:

#include <Arduino.h>
#include "do-something.h"

int doSomething(void) {
  return 4;
};

Probémoslo con arduino_ci. Primero, necesita agregar un Gemfile en el directorio base de su biblioteca con el siguiente contenido:

source 'https://rubygems.org'
gem 'arduino_ci', '~> 0.1.7'

A continuación, ejecute bundle install.

A continuación, cree un directorio llamado test/. (Cada archivo .cpp que coloque aquí se considerará un conjunto de pruebas separado). Vamos a crear una prueba por ahora, en 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.

Eso es todo. Si esa assertEqual sintaxis y estructura de prueba parece familiar, es porque I adopted some of Matthew Murdoch's ArduinoUnit library{[18]]} que se refirió en su respuesta.

Ahora está listo para ejecutar bundle exec arduino_ci_remote.rb, que ejecutará esas pruebas. Podría dar salida algo como esto:

$ 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/[email protected]/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/[email protected]/4.9.4_1     --libdir=/usr/local/Cellar/[email protected]/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

Ejecutar el mismo código como parte de un trabajo de CI en Travis CI (por ejemplo, para que pueda activarlo desde las solicitudes de extracción de GitHub) también es simple. Simplemente agregue esto a su archivo .travis.yml:

language: ruby
script:
   - bundle install
   - bundle exec arduino_ci_remote.rb

Por supuesto, hay mucho más poder y flexibilidad para esta biblioteca de CI de lo que me estoy metiendo aquí. Aquí hay algunos otros ejemplos:

 2
Author: Ian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-23 12:17:44

Puede usar emulare - puede arrastrar y soltar un microcontrolador en un diagrama y ejecutar su código en Eclipse. La documentación en el sitio web le dice cómo configurarlo.

 1
Author: Imre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-20 09:09:30

Use Proteus VSM con una biblioteca Arduino para depurar su código o probarlo.

Es una práctica recomendada antes de incorporar su código, pero asegúrese de usar los tiempos porque la simulación no se ejecuta en tiempo real, ya que se ejecutan en el tablero.

 1
Author: sathish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-07 17:16:57

Prueba Autodesk circuit simulator. Permite probar código y circuitos Arduino con muchos otros componentes de hardware.

 1
Author: Sidhant Goyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-07 17:18:00