1

The question is maybe not explicit enough.
I'm trying to write tests for an Arduino program, using VSCode with Platformio.

Here is an example of a function I want to test:

#include "flash.h"
#include <Arduino.h>

void flashXTimes(
    uint8_t LEDPin,
    uint16_t numberOfFlashes,
    uint16_t onDuration,
    uint16_t offDuration)
{
  for (uint16_t i = 0; i < numberOfFlashes; i++)
  {
    digitalWrite(LEDPin, HIGH);
    delay(onDuration);
    digitalWrite(LEDPin, LOW);
    delay(offDuration);
  }
}

I want to check that when I call this function with numberOfFlashes 3, it will actually flash 3 times. Sure the code is so easy that tests aren't really needed, but I want to do them anyway.

So ChatGPT gave me a hint of using a mock digital write

static uint32_t digitalWriteCalls = 0;
void digitalWriteMock(uint8_t pin, uint8_t val) {
    digitalWriteCalls++;
}

but then told me to digitalWrite = &digitalWriteMock; which would work fine in Python, but not in C++.

By following the Platformio testing guide using Unity, I got tests going, but nothing meaningful.
I'd appreciate some help in getting started with testing in C++/Arduino

Thomas J
  • 146
  • 10
  • Arduino is C++, not C. – jabaa Mar 18 '23 at 14:57
  • If I understand what you want, then you have to run the test on a test 'framework'. for the test on PC you can't use Arduino core's Arduino.h, you have to write your own Arduino.h with a different implementation of digitalWrite – Juraj Mar 18 '23 at 15:41
  • @Juraj you can actually run tests on the Arduino with Platformio and Unity: https://docs.platformio.org/en/stable/advanced/unit-testing/runner.html#remote-test-runner – Thomas J Mar 18 '23 at 16:03
  • but for that you don't need to add a mock function to your sketch. https://docs.platformio.org/en/stable/advanced/unit-testing/runner.html#embedded – Juraj Mar 18 '23 at 16:57
  • what I want to test is how many times digitalWrite was called – Thomas J Mar 18 '23 at 17:00

1 Answers1

0

Following up to ChatGPT's answer, you'd want to define a variable of type "pointer to function". When you test, that variable points to the test function. When you run "for real", that variable points to the real function.

For example:

void (*digitalWriteFunction)(uint8_t, uint8_t);
if (testing) {
    digitalWriteFunction = &digitalWriteMock;
}
else {
    digitalWriteFunction = &digitalWrite;
}

// From here on, use digitalWriteFunction pretty much the same way you'd call a function:
(*digitalWriteFunction)(LEDPin, HIGH);

Obviously, in your mock function, you can do whatever you want like confirm what are the values of the arguments passed, etc.

screwnut
  • 1,367
  • 7
  • 26
  • Thanks, that helped me a bit already, I made it work in the test file with #ifdef PIO_UNIT_TESTING and a simple digitalWriteFunction(LED_BUILTIN, HIGH); and could assert that afterwards digitalWriteCalls==1. But for some reason I don't understand, if I do it in my flash.cpp file, and I include flash.h in my test file, I get undefined reference to `flashXTimes` – Thomas J Mar 18 '23 at 16:20
  • I managed to add the mock conditionally in my code, so in "production" mode everything works fine. In testing, the Arduino seems to freeze – Thomas J Mar 18 '23 at 16:47
  • Found out that as soon as I use the delay function, the communication between the Arduino and platformio will break – Thomas J Mar 18 '23 at 17:20