How can I unit test Arduino code?

Viewed 74191

I'd like to be able to unit test my Arduino code. Ideally, I would be able to run any tests without having to upload the code to the Arduino. What tools or libraries can help me with this?

There is an Arduino emulator in development which could be useful, but it doesn't yet seem to be ready for use.

AVR Studio from Atmel contains a chip simulator which could be useful, but I can't see how I would use it in conjunction with the Arduino IDE.

20 Answers

In the absence of any pre-existing unit test frameworks for Arduino, I have created ArduinoUnit. Here's a simple Arduino sketch demonstrating its use:

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

I have considerable success unit testing my PIC code by abstracting out the hardware access and mocking it in my tests.

For example, I abstract PORTA with

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

Then SetPortA can easily be mocked, without adding overhead code in the PIC version.

Once the hardware abstraction has been tested a while I soon find that generally code goes from the test rig to the PIC and works first time.

Update:

I use a #include seam for the unit code, #including the unit code in a C++ file for the test rig, and a C file for the target code.

As an example I want to multiplex four 7 segment displays, one port driving the segments and a second selecting the display. The display code interfaces with the displays via SetSegmentData(char) and SetDisplay(char). I can mock these in my C++ test rig and check that I get the data I expect. For the target I use #define so that I get a direct assignment without the overhead of a function call

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

simavr is an AVR simulator using avr-gcc.

It already supports a few ATTiny and ATMega microcontrollers, and - according to the author - it's easy to add some more.

In the examples lies simduino, an Arduino emulator. It supports running the Arduino bootloader and can be programmed with avrdude through Socat (a modified Netcat).

I am not aware of any platform which can test Arduino code.

However, there is the Fritzing platform, which you can use to model the hardware and later on export PCB diagrams and stuff.

Worth checking.

In basic Arduino is written with C and C++, even libraries of arduino are written in C and C++. So,in simple terms just handle the code as C and C++ and try doing the unit testing. Here, by the word "handle" I mean you to change all the basic syntax like serial.println to sysout, pinmode to varaibles, void loop to while() loop which breaks either in keystock or after some iteration.

I know this is little a long process and not so straight forward.On my personal experience, once you get to do with it, this turns to be more reliable.

-Nandha_Frost

In case you are interested in running an INO sketch and checkout the serial output, I have a working implementation of that in my Arduino NMEA checksum project.

The following script takes the file and uses Arduino CLI to compile it to a HEX file which is then loaded to SimAVR which evaluates it and prints the serial output. Since all Arduino programs run forever without really having an option of killing themselves (exit(0) doesn't work), I let the sketch run for a few seconds and then diff the captured output with expected output.

Download and extract Arduino CLI (in this case version 0.5.0 - latest at the time of writing):

curl -L https://github.com/arduino/arduino-cli/releases/download/0.5.0/arduino-cli_0.5.0_Linux_64bit.tar.gz -o arduino-cli.tar.gz
tar -xvzf arduino-cli.tar.gz

Now you can update the index and install the appropriate core:

./arduino-cli core update-index
./arduino-cli core install arduino:avr

Assuming your sketch is named nmea-checksum.ino, to get ELF and HEX, run:

./arduino-cli compile -b arduino:avr:uno nmea-checksum.ino

Next up, SimAVR to run the HEX (or ELF) - I build from source because the latest release didn't work for me:

sudo apt-get update
sudo apt-get install -y build-essential libelf-dev avr-libc gcc-avr freeglut3-dev libncurses5-dev pkg-config
git clone https://github.com/buserror/simavr.git
cd simavr
make

Successful compilation will give you simavr/run_avr which you can use to run the sketch. Like I said, timeout it otherwise it will never terminate:

cd simavr
timeout 10 ./run_avr -m atmega168 -f 16000000 ../../nmea-checksum.ino.arduino.avr.uno.elf &> nmea-checksum.ino.clog || true

The generated file will have ANSI color code control characters wrapping the serial output, to get rid of those:

cat nmea-checksum.ino.clog | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > nmea-checksum.ino.log
cat nmea-checksum.ino.log

Now all you need to do is compared this file to a known good file:

diff nmea-checksum.ino.log ../../nmea-checksum.ino.test

If there are no differences, diff will exit with code 0, otherwise the script will fail.

Related