2

I have an Arduino project where the file structure looks like this

myProject/
    myProject.ino
    ImportantClass1.hpp 
    ImportantClass1.cpp
    ImportantClass2.hpp 
    ImportantClass2.cpp
    Etc….

It compiles and runs fine. No problem pulling the cpp and hpp files into the ino program. However to really make sure of reliability I want to make additional ino files for unit testing of importantClass1 & etc. I have made files importantClass1UnitTest.ino & importantClass2UnitTest.ino however these can’t be in the same dir as the respective source files as the arduino compiler requires the ino file and the dir to have the same name.

The tests run when I move the files around. But I am not happy with that, I want to be able to run the tests at any time with the standard arduino compiler without having to script filecopy commands.

If I put the unit test in its own dir separate to the class source and #include using the full path it also works. However this solutions is not portable, when I (or any collaborator) pull the project from git hub on any other computer the paths are wrong and it doesn’t work.

Where am I going wrong? How can I do this so as to avoid moving/copying files and also avoid using full paths?

7
  • I do not think there is a standard “Arduino way” of storing unit tests, and this is a great question that may, hopefully, help reveal best practices. I would suggest to #include a relative (rather than absolute) path. Jun 19, 2022 at 19:09
  • Thanks @EdgarBonet I have tried relative paths and can’t get them to work. If the path is relative to the location of unitTest.ino file then the relative path has to start with ../../location of source. But this doesn’t work for me. Where would the relative path be relative to?
    – Hubert B
    Jun 19, 2022 at 21:37
  • Without a working environment, I would use "../myProject", if "myProject" is on the same level as "importantClass1UnitTest". Jun 20, 2022 at 6:35
  • @EdgarBonet, Arduino IDE/CLI compiles and builds in a temporary folder. relative paths don't work.
    – Juraj
    Jun 20, 2022 at 13:36
  • Confirmed. Relative paths don't work.
    – Hubert B
    Jun 20, 2022 at 17:26

2 Answers 2

1

One way to do it is to use preprocessor conditionals. Name your project file and unit-test files with .cpp extensions and put them in a subfolder (called "sources" in my example). Then your .ino file would only be used to instruct the preprocessor which of the several "main" file to start compiling with:

myProject.ino:

/*
 * myProject.ino
 * define which "main" CPP file to compile:
 */

#define PRODUCTION
// #define UNITTEST1
// #define UNITTEST2
// #define UNITTEST3

// The compilation starts here with the requested "main" file:
#if defined PRODUCTION
#include "sources/myProject.cpp"

#elif defined UNITTEST1
#include "sources/unitTest1.cpp"

#elif defined UNITTEST2
#include "sources/unitTest2.cpp"

#elif defined UNITTEST3
#include "sources/unitTest3.cpp"

#else
// If nothing defined, compile for production
#include "sources/myProject.cpp"
#endif

/* END */

Only the .ino file would need to be edited to compile one of the unit tests, and only one project file would be needed.

Update: "did you try it? "

Yes, and it does work. The only caveat I'd add is: don't name your subfolder "src" - that seems to be a magic-name to the IDE, and you'll get complaints of compilation errors (multiple definitions) if you use it. And further, if you try it, you can't get back simply by changing the folder's name (on disk and in the code); you'll have to restart the IDE as well.
I tested it with v1.8.19 of the IDE.

4
  • Given that the two files I placed in the folder were a complete Arduino 'blink' sketch and a complete 'Hello, World' sketch, but with .cpp extensions,, and that selecting one or the other as I showed in the my answer and compiling and downloading produced the expected results, than, yeah, I can definitely say they were compiled. But don't take my word for it; try it yourself.
    – JRobert
    Jun 20, 2022 at 17:12
  • sorry. yes. the cpp was not a cpp. it was just an included file. it could have txt or ino as filename extension.
    – Juraj
    Jun 20, 2022 at 17:24
  • Thanks for the answer. I am not going to do it this way though. Looks like I will have to make test runner scripts that overcome the lack of support for relative paths by copying files from the project dir to the unit test dir and maybe running the unit tests with the Arduino CLI.
    – Hubert B
    Jun 20, 2022 at 18:05
  • 2
    @HubertB, it would be great if you can share an example when you can of your intended alternative solution as another answer here.
    – RowanP
    Jun 20, 2022 at 21:18
1

OK. Update, better late than never. I used soft links to overcome this problem.

The final directory structure is like this:

myProject/
    .git/
    myProject.ino
    Class1.hpp 
    Class1.cpp
    Class2.hpp 
    Class2.cpp
    ...
    UnitTests/TestClass1/TestClass1.ino
    UnitTests/TestClass1/Class1.cpp -> ../../Class1.cpp
    UnitTests/TestClass1/Class1.h   -> ../../Class1.h
    ...

Both the main program and all the unit tests run fine when compiled in the Arduino compiler and there is only one copy of the class files that I want to test.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.