Unit tests are as important to a firmware/program (“application”) as the production source code. As with the regular code, you need to give careful thought to where the tests reside, both physically and logically, in relation to the code under test. If you put unit tests in the wrong place, the tests you have written may not be run.
Similarly, if you do not devise ways to reuse parts of your tests and use test hierarchy, you will end up with test code that is either unmaintainable or hard to understand. So, what makes a good test?
Tests should be independent and repeatable. It is a pain to debug a test that succeeds or fails as a result of other tests. PlatformIO isolates the tests by running each of them as a separate application. When a test fails, PlatformIO allows you to run it in isolation for quick debugging.
Tests should not depend on the main application source code. In PlatformIO, each test is an independent application and should contain its own
setup() / loop()for Arduino,
app_main()for Espressif IoT Development Framework). Linking the main application source code from src_dir with a test suite code will lead to multiple compilation errors. Hence, the Shared Code is disabled by default.
Tests should be well organized and reflect the structure of the tested code. PlatformIO lets you organize tests using nested folders. The only folder with a name prefixed by
test_is nominated for unit testing and is an independent test/application. See Test Hierarchy.
New in version 6.0.
PlatformIO looks for the tests in the project test_dir.
The only folder with a name prefixed by
test_ is nominated for unit testing
and should be an independent test/application with its own
setup() / loop() for Arduino,
for Espressif IoT Development Framework). Nested folders are supported and will help you
to organize your tests.
The root test_dir and a folder of the active test are
automatically added to the
CPPPATH scope (C Preprocessor Search Path).
Also, C/C++ files located in the root of test_dir will
be compiled together with the active test source files. The root
test_dir is useful for placing configuration
and extra C/C++ files related to the Testing Frameworks.
Example of Pizza Project
Let’s demystify how PlatformIO handles unit tests using a virtual “Pizza Project” having the following structure:
project_dir ├── include │ └── pizza_config.h ├── lib │ ├── Cheese │ │ ├── include │ │ │ └── cheese.h │ │ └── src │ │ └── cheese.cpp │ ├── Dough │ │ ├── include │ │ │ └── dough.h │ │ └── src │ │ └── dough.cpp │ └── Sauce │ ├── include │ │ └── sauce.h │ └── src │ └── sauce.cpp ├── platformio.ini ├── src │ └── baking.cpp └── test ├── embedded │ ├── components │ │ └── sauce │ │ └── test_tomatos │ │ └── prepare.cpp │ ├── stove │ │ ├── test_humidity │ │ │ ├── measure.cpp │ │ │ └── sensor.cpp │ │ └── test_temperature │ │ ├── measure.cpp │ │ └── sensor │ │ ├── sensor.cpp │ │ └── sensor.h │ ├── unity_config.cpp │ └── unity_config.h └── test_ingredients ├── include │ ├── cheese.h │ ├── vegetables.h │ ├── water.h │ ├── wheat.h │ └── yeast.h └── weighing.cpp
The main source code (“pizza baking”) is located in the
This is a production code. A cooking process consists of multiple subprocesses
and depends on the components located in the
lib folder. Each pizza’s component
can be tested independently using unit testing.
The Pizza Project consists of 4 independent tests:
PlatformIO treats each test as an independent micro project with its own source
files and subfolders. You can include local header files using the relative paths.
For example, the
test_ingredients/weighing.cpp source file includes
unity_config.cpp files are located in the
embedded folder and are common for the
This allows you to run a group of tests only on the embedded target and route
a test result output to the custom Serial/UART interface.
On the other hand, the
test_ingredients test uses the default Unity configuration
provided by PlatformIO. For more details, please check the documentation for the
Unity testing framework.