ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively.
Add normal test cases
---------------------
Unit tests are added in the ``test`` subdirectory of the respective component.
Tests are added in C files, a single C file can include multiple test cases.
Test files start with the word "test".
The test file should include unity.h and the header for the C module to be tested.
Tests are added in a function in the C file as follows::
TEST_CASE("test name", "[module name]"
{
// Add test here
}
First argument is a descriptive name for the test, second argument is an identifier in square brackets.
Identifiers are used to group related test, or tests with specific properties.
There is no need to add a main function with ``UNITY_BEGIN()`` and ``UNITY_END()`` in each test case.
``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``UNITY_END()``.
The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt <component-directories-cmake>`, since they are themselves,
components. ESP-IDF uses the test framework ``unity`` and should be specified as a requirement for the component. Normally, components
:ref:`should list their sources manually <cmake-file-globbing>`; for component tests however, this requirement is relaxed and the
use of ``COMPONENT_SRCDIRS`` is advised.
Overall, the minimal ``test`` subdirectory CMakeLists.txt file may look like as follows:
See http://www.throwtheswitch.org/unity for more information about writing tests in Unity.
Add multiple devices test cases
-------------------------------
The normal test cases will be executed on one DUT (Device Under Test). Components need to communicate with each other (like GPIO, SPI ...) can't be tested with normal test cases.
Multiple devices test cases support writing and running test with multiple DUTs.
TEST_CASE_MULTIPLE_DEVICES("gpio multiple devices test example", "[driver]", gpio_master_test, gpio_slave_test);
The macro ``TEST_CASE_MULTIPLE_DEVICES`` is used to declare multiple devices test cases.
First argument is test case name, second argument is test case description.
From the third argument, upto 5 test functions can be defined, each function will be the entry point of tests running on each DUT.
Running test cases from different DUTs could require synchronizing between DUTs. We provide ``unity_wait_for_signal`` and ``unity_send_signal`` to support synchronizing with UART.
As the secnario in the above example, slave should get GPIO level after master set level. DUT UART console will prompt and requires user interaction:
DUT1 (master) console::
Waiting for signal: [output high level]!
Please press "Enter" key to once any board send this signal.
DUT2 (slave) console::
Send signal: [output high level]!
Once the signal is set from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level.
Add multiple stages test cases
-------------------------------
The normal test cases are expected to finish without reset (or only need to check if reset happens). Sometimes we want to run some specific test after certain kinds of reset.
For example, we want to test if reset reason is correct after wakeup from deep sleep. We need to create deep sleep reset first and then check the reset reason.
To support this, we can define multiple stages test case, to group a set of test functions together::
static void trigger_deepsleep(void)
{
esp_sleep_enable_timer_wakeup(2000);
esp_deep_sleep_start();
}
void check_deepsleep_reset_reason()
{
RESET_REASON reason = rtc_get_reset_reason(0);
TEST_ASSERT(reason == DEEPSLEEP_RESET);
}
TEST_CASE_MULTIPLE_STAGES("reset reason check for deepsleep", "[esp32]", trigger_deepsleep, check_deepsleep_reset_reason);
Multiple stages test cases present a group of test functions to users. It need user interactions (select case and select different stages) to run the case.
Building unit test app
----------------------
Follow the setup instructions in the top-level esp-idf README.
Make sure that IDF_PATH environment variable is set to point to the path of esp-idf top-level directory.
Change into tools/unit-test-app directory to configure and build it:
*`idf.py -T all build` - build unit test app with tests for each component having tests in the ``test`` subdirectory.
*`idf.py -T xxx build` - build unit test app with tests for specific components.
*`idf.py -T all -E xxx build` - build unit test app with all unit tests, except for unit tests of some components. (For instance: `idf.py -T all -E ulp -E mbedtls build` - build all unit tests exludes ulp and mbedtls components).
You can also run ``idf.py -T all flash`` or ``idf.py -T xxx flash`` to build and flash. Everything needed will be rebuilt automatically before flashing.