1.. _test-framework: 2 3Test Framework 4############### 5 6The Zephyr Test Framework (Ztest) provides a simple testing framework intended 7to be used during development. It provides basic assertion macros and a generic 8test structure. 9 10The framework can be used in two ways, either as a generic framework for 11integration testing, or for unit testing specific modules. 12 13Creating a test suite 14********************* 15 16Using Ztest to create a test suite is as easy as calling the :c:macro:`ZTEST_SUITE`. The macro 17accepts the following arguments: 18 19* ``suite_name`` - The name of the suite. This name must be unique within a single binary. 20* :c:type:`ztest_suite_predicate_t` - An optional predicate function to allow choosing when the 21 test will run. The predicate will get a pointer to the global state passed in through 22 :c:func:`ztest_run_all` and should return a boolean to decide if the suite should run. 23* :c:type:`ztest_suite_setup_t` - An optional setup function which returns a test fixture. This 24 will be called and run once per test suite run. 25* :c:type:`ztest_suite_before_t` - An optional before function which will run before every single 26 test in this suite. 27* :c:type:`ztest_suite_after_t` - An optional after function which will run after every single 28 test in this suite. 29* :c:type:`ztest_suite_teardown_t` - An optional teardown function which will run at the end of 30 all the tests in the suite. 31 32Below is an example of a test suite using a predicate: 33 34.. code-block:: C 35 36 #include <zephyr/ztest.h> 37 #include "test_state.h" 38 39 static bool predicate(const void *global_state) 40 { 41 return ((const struct test_state*)global_state)->x == 5; 42 } 43 44 ZTEST_SUITE(alternating_suite, predicate, NULL, NULL, NULL, NULL); 45 46Adding tests to a suite 47*********************** 48 49There are 5 macros used to add a test to a suite, they are: 50 51* :c:macro:`ZTEST` ``(suite_name, test_name)`` - Which can be used to add a test by ``test_name`` to a 52 given suite by ``suite_name``. 53* :c:macro:`ZTEST_P` ``(suite_name, test_name)`` - Add a parameterized test to a given suite by specifying 54 the ``suite_name`` and ``test_name``. You can then access the passed parameter within 55 the body of the test using the ``data`` pointer. 56* :c:macro:`ZTEST_USER` ``(suite_name, test_name)`` - Which behaves the same as :c:macro:`ZTEST`, only 57 that when :kconfig:option:`CONFIG_USERSPACE` is enabled, then the test will be run in a userspace 58 thread. 59* :c:macro:`ZTEST_F` ``(suite_name, test_name)`` - Which behaves the same as :c:macro:`ZTEST`, only 60 that the test function will already include a variable named ``fixture`` with the type 61 ``<suite_name>_fixture``. 62* :c:macro:`ZTEST_USER_F` ``(suite_name, test_name)`` - Which combines the fixture feature of 63 :c:macro:`ZTEST_F` with the userspace threading for the test. 64 65Test fixtures 66============= 67 68Test fixtures can be used to help simplify repeated test setup operations. In many cases, tests in 69the same suite will require some initial setup followed by some form of reset between each test. 70This is achieved via fixtures in the following way: 71 72.. code-block:: C 73 74 #include <zephyr/ztest.h> 75 76 struct my_suite_fixture { 77 size_t max_size; 78 size_t size; 79 uint8_t buff[1]; 80 }; 81 82 static void *my_suite_setup(void) 83 { 84 /* Allocate the fixture with 256 byte buffer */ 85 struct my_suite_fixture *fixture = malloc(sizeof(struct my_suite_fixture) + 255); 86 87 zassume_not_null(fixture, NULL); 88 fixture->max_size = 256; 89 90 return fixture; 91 } 92 93 static void my_suite_before(void *f) 94 { 95 struct my_suite_fixture *fixture = (struct my_suite_fixture *)f; 96 memset(fixture->buff, 0, fixture->max_size); 97 fixture->size = 0; 98 } 99 100 static void my_suite_teardown(void *f) 101 { 102 free(f); 103 } 104 105 ZTEST_SUITE(my_suite, NULL, my_suite_setup, my_suite_before, NULL, my_suite_teardown); 106 107 ZTEST_F(my_suite, test_feature_x) 108 { 109 zassert_equal(0, fixture->size); 110 zassert_equal(256, fixture->max_size); 111 } 112 113Using memory allocated by a test fixture in a userspace thread, such as during execution of 114:c:macro:`ZTEST_USER` or :c:macro:`ZTEST_USER_F`, requires that memory to be declared userspace 115accessible. This is because the fixture memory is owned and initialized by kernel space. The Ztest 116framework provides the :c:macro:`ZTEST_DMEM` and :c:macro:`ZTEST_BMEM` macros for use of such 117user/kernel space shared memory. 118 119Advanced features 120***************** 121 122Test result expectations 123======================== 124 125Some tests were made to be broken. In cases where the test is expected to fail or skip due to the 126nature of the code, it's possible to annotate the test as such. For example: 127 128 .. code-block:: C 129 130 #include <zephyr/ztest.h> 131 132 ZTEST_SUITE(my_suite, NULL, NULL, NULL, NULL, NULL); 133 134 ZTEST_EXPECT_FAIL(my_suite, test_fail); 135 ZTEST(my_suite, test_fail) 136 { 137 /** This will fail the test */ 138 zassert_true(false, NULL); 139 } 140 141 ZTEST_EXPECT_SKIP(my_suite, test_skip); 142 ZTEST(my_suite, test_skip) 143 { 144 /** This will skip the test */ 145 zassume_true(false, NULL); 146 } 147 148In this example, the above tests should be marked as failed and skipped respectively. Instead, 149Ztest will mark both as passed due to the expectation. 150 151Test rules 152========== 153 154Test rules are a way to run the same logic for every test and every suite. There are a lot of cases 155where you might want to reset some state for every test in the binary (regardless of which suite is 156currently running). As an example, this could be to reset mocks, reset emulators, flush the UART, 157etc.: 158 159.. code-block:: C 160 161 #include <zephyr/fff.h> 162 #include <zephyr/ztest.h> 163 164 #include "test_mocks.h" 165 166 DEFINE_FFF_GLOBALS; 167 168 DEFINE_FAKE_VOID_FUN(my_weak_func); 169 170 static void fff_reset_rule_before(const struct ztest_unit_test *test, void *fixture) 171 { 172 ARG_UNUSED(test); 173 ARG_UNUSED(fixture); 174 175 RESET_FAKE(my_weak_func); 176 } 177 178 ZTEST_RULE(fff_reset_rule, fff_reset_rule_before, NULL); 179 180A custom ``test_main`` 181====================== 182 183While the Ztest framework provides a default :c:func:`test_main` function, it's possible that some 184applications will want to provide custom behavior. This is particularly true if there's some global 185state that the tests depend on and that state either cannot be replicated or is difficult to 186replicate without starting the process over. For example, one such state could be a power sequence. 187Assuming there's a board with several steps in the power-on sequence a test suite can be written 188using the ``predicate`` to control when it would run. In that case, the :c:func:`test_main` 189function can be written as follows: 190 191.. code-block:: C 192 193 #include <zephyr/ztest.h> 194 195 #include "my_test.h" 196 197 void test_main(void) 198 { 199 struct power_sequence_state state; 200 201 /* Only suites that use a predicate checking for phase == PWR_PHASE_0 will run. */ 202 state.phase = PWR_PHASE_0; 203 ztest_run_all(&state, false, 1, 1); 204 205 /* Only suites that use a predicate checking for phase == PWR_PHASE_1 will run. */ 206 state.phase = PWR_PHASE_1; 207 ztest_run_all(&state, false, 1, 1); 208 209 /* Only suites that use a predicate checking for phase == PWR_PHASE_2 will run. */ 210 state.phase = PWR_PHASE_2; 211 ztest_run_all(&state, false, 1, 1); 212 213 /* Check that all the suites in this binary ran at least once. */ 214 ztest_verify_all_test_suites_ran(); 215 } 216 217 218Quick start - Integration testing 219********************************* 220 221A simple working base is located at :zephyr_file:`samples/subsys/testsuite/integration`. 222To make a test application for the **bar** component of **foo**, you should copy the 223sample folder to ``tests/foo/bar`` and edit files there adjusting for your test 224application's purposes. 225 226To build and execute all applicable test scenarios defined in your test application 227use the :ref:`Twister <twister_script>` tool, for example: 228 229.. code-block:: console 230 231 ./scripts/twister -T tests/foo/bar/ 232 233To select just one of the test scenarios, run Twister with ``--scenario`` command: 234 235.. code-block:: console 236 237 ./scripts/twister --scenario tests/foo/bar/your.test.scenario.name 238 239In the command line above ``tests/foo/bar`` is the path to your test application and 240``your.test.scenario.name`` references a test scenario defined in :file:`testcase.yaml` 241file, which is like ``sample.testing.ztest`` in the boilerplate test suite sample. 242 243See :ref:`Twister test project diagram <twister_test_project_diagram>` for more details 244on how Twister deals with Ztest application. 245 246The sample contains the following files: 247 248CMakeLists.txt 249 250.. literalinclude:: ../../../samples/subsys/testsuite/integration/CMakeLists.txt 251 :language: CMake 252 :linenos: 253 254testcase.yaml 255 256.. literalinclude:: ../../../samples/subsys/testsuite/integration/testcase.yaml 257 :language: yaml 258 :linenos: 259 260prj.conf 261 262.. literalinclude:: ../../../samples/subsys/testsuite/integration/prj.conf 263 :language: text 264 :linenos: 265 266src/main.c 267 268.. literalinclude:: ../../../samples/subsys/testsuite/integration/src/main.c 269 :language: c 270 :linenos: 271 272.. contents:: 273 :depth: 1 274 :local: 275 :backlinks: top 276 277 278 279A test application may consist of multiple test suites that 280either can be testing functionality or APIs. Functions implementing a test case 281should follow the guidelines below: 282 283* Test cases function names should be prefixed with **test_** 284* Test cases should be documented using doxygen 285* Test case function names should be unique within the section or component being 286 tested 287 288For example: 289 290.. code-block:: C 291 292 /** 293 * @brief Test Asserts 294 * 295 * This test case verifies the zassert_true macro. 296 */ 297 ZTEST(my_suite, test_assert) 298 { 299 zassert_true(1, "1 was false"); 300 } 301 302Listing Tests 303============= 304 305Tests (test applications) in the Zephyr tree consist of many test scenarios that run as 306part of a project and test similar functionality, for example an API or a 307feature. The ``twister`` script can parse the test scenarios, suites and cases in all 308test applications or a subset of them, and can generate reports on a granular 309level, i.e. if test cases have passed or failed or if they were blocked or skipped. 310 311Twister parses the source files looking for test case names, so you 312can list all kernel test cases, for example, by running: 313 314.. code-block:: console 315 316 ./scripts/twister --list-tests -T tests/kernel 317 318Skipping Tests 319============== 320 321Special- or architecture-specific tests cannot run on all 322platforms and architectures, however we still want to count those and 323report them as being skipped. Because the test inventory and 324the list of tests is extracted from the code, adding 325conditionals inside the test suite is sub-optimal. Tests that need 326to be skipped for a certain platform or feature need to explicitly 327report a skip using :c:func:`ztest_test_skip` or :c:macro:`Z_TEST_SKIP_IFDEF`. If the test runs, 328it needs to report either a pass or fail. For example: 329 330.. code-block:: C 331 332 #ifdef CONFIG_TEST1 333 ZTEST(common, test_test1) 334 { 335 zassert_true(1, "true"); 336 } 337 #else 338 ZTEST(common, test_test1) 339 { 340 ztest_test_skip(); 341 } 342 #endif 343 344 ZTEST(common, test_test2) 345 { 346 Z_TEST_SKIP_IFDEF(CONFIG_BUGxxxxx); 347 zassert_equal(1, 0, NULL); 348 } 349 350 ZTEST_SUITE(common, NULL, NULL, NULL, NULL, NULL); 351 352.. _ztest_unit_testing: 353 354Quick start - Unit testing 355************************** 356 357Ztest can be used for unit testing. This means that rather than including the 358entire Zephyr OS for testing a single function, you can focus the testing 359efforts into the specific module in question. This will speed up testing since 360only the module will have to be compiled in, and the tested functions will be 361called directly. 362 363To setup unit tests you have to add a CMakeLists.txt, a testcases.yml and a 364prj.conf to the directory containing the unit test source files. The resulting 365binary from this directory is build with the -DBOARD=unit_testing. When twister 366is invoked the script zephyr/scripts/pylib/twister/twisterlib/testplan.py 367filters out all testcases.yml in which type: unit is not set. Only unit tests 368are executed with a firmware build with BOARD=unit_testing. 369 370.. note:: 371 Unit tests are run as **native** applications on the host and are therefore 372 subject to similar :ref:`limitations <posix_arch_limitations>` as documented 373 for the :ref:`POSIX architecture<Posix arch>`. Running unit tests is 374 therefore only supported for Linux. To run unit tests on Windows or macOS 375 it is necessary to use containers or Virtual Machines running a Linux guest. 376 Follow the same instructions as for the 377 :ref:`POSIX Arch dependencies<posix_arch_deps>`. 378 379CMakeLists.txt 380============== 381 382In order to declare the unit tests present in a source folder, you need to add 383the relevant source files to the ``testbinary`` target from the CMake 384:zephyr_file:`unittest <cmake/modules/unittest.cmake>` component. See a minimal 385example below: 386 387.. code-block:: cmake 388 389 cmake_minimum_required(VERSION 3.20.0) 390 391 project(app) 392 find_package(Zephyr COMPONENTS unittest REQUIRED HINTS $ENV{ZEPHYR_BASE}) 393 target_sources(testbinary PRIVATE main.c) 394 395Since you won't be including basic kernel data structures that most code 396depends on, you have to provide function stubs in the test. Ztest provides 397some helpers for mocking functions, as demonstrated below. 398 399In a unit test, mock objects can simulate the behavior of complex real objects 400and are used to decide whether a test failed or passed by verifying whether an 401interaction with an object occurred, and if required, to assert the order of 402that interaction. 403 404testcases.yaml 405============== 406 407You have to set the value for the key "type" to "unit" in the testcase.yaml 408 409.. code-block:: yaml 410 411 tests: 412 testscenario.testsuite: 413 tags: your_tag 414 type: unit 415 416prj.conf 417======== 418 419For unit tests this contains usually only 420 421.. code-block:: kconfig 422 423 CONFIG_ZTEST=y 424 425If your unit tests require additional libraries (e.g. math-lib) you will have to 426add them either via the CMakeLists.txt or in the testcase.yaml: 427 428.. code-block:: yaml 429 430 tests: 431 testscenario.testsuite: 432 tags: your_tag 433 type: unit 434 extra_args: 435 - EXTRA_LDFLAGS="-lm" 436 437Examples of unit tests can be found in the :zephyr_file:`tests/unit/` folder. 438 439Best practices for declaring the test suite 440******************************************* 441 442*twister* and other validation tools need to obtain the list of 443test cases that a Zephyr *ztest* test image will expose. 444 445.. admonition:: Rationale 446 447 This all is for the purpose of traceability. It's not enough to 448 have only a semaphore test application. We also need to show that we 449 have testpoints for all APIs and functionality, and we trace back 450 to documentation of the API, and functional requirements. 451 452 The idea is that test reports show results for every test case 453 as passed, failed, blocked, or skipped. Reporting on only the 454 high-level test application, particularly when tests do too 455 many things, is too vague. 456 457Other questions: 458 459- Why not pre-scan with CPP and then parse? or post scan the ELF file? 460 461 If C pre-processing or building fails because of any issue, then we 462 won't be able to tell the subcases. 463 464- Why not declare them in the YAML test configuration? 465 466 A separate test case description file would be harder to maintain 467 than just keeping the information in the test source files 468 themselves -- only one file to update when changes are made 469 eliminates duplication. 470 471Stress test framework 472********************* 473 474Zephyr stress test framework (Ztress) provides an environment for executing user 475functions in multiple priority contexts. It can be used to validate that code is 476resilient to preemptions. The framework tracks the number of executions and preemptions 477for each context. Execution can have various completion conditions like timeout, 478number of executions or number of preemptions. 479 480The framework is setting up the environment by creating the requested number of threads 481(each on different priority), optionally starting a timer. For each context, a user 482function (different for each context) is called and then the context sleeps for 483a randomized amount of system ticks. The framework is tracking CPU load and adjusts sleeping 484periods to achieve higher CPU load. In order to increase the probability of preemptions, 485the system clock frequency should be relatively high. The default 100 Hz on QEMU x86 486is much too low and it is recommended to increase it to 100 kHz. 487 488The stress test environment is setup and executed using :c:macro:`ZTRESS_EXECUTE` which 489accepts a variable number of arguments. Each argument is a context that is 490specified by :c:macro:`ZTRESS_TIMER` or :c:macro:`ZTRESS_THREAD` macros. Contexts 491are specified in priority descending order. Each context specifies completion 492conditions by providing the minimum number of executions and preemptions. When all 493conditions are met and the execution has completed, an execution report is printed 494and the macro returns. Note that while the test is executing, a progress report is 495periodically printed. 496 497Execution can be prematurely completed by specifying a test timeout (:c:func:`ztress_set_timeout`) 498or an explicit abort (:c:func:`ztress_abort`). 499 500User function parameters contains an execution counter and a flag indicating if it is 501the last execution. 502 503The example below presents how to setup and run 3 contexts (one of which is k_timer 504interrupt handler context). Completion criteria is set to at least 10000 executions 505of each context and 1000 preemptions of the lowest priority context. Additionally, 506the timeout is configured to complete after 10 seconds if those conditions are not met. 507The last argument of each context is the initial sleep time which will be adjusted throughout 508the test to achieve the highest CPU load. 509 510 .. code-block:: C 511 512 ztress_set_timeout(K_MSEC(10000)); 513 ZTRESS_EXECUTE(ZTRESS_TIMER(foo_0, user_data_0, 10000, Z_TIMEOUT_TICKS(20)), 514 ZTRESS_THREAD(foo_1, user_data_1, 10000, 0, Z_TIMEOUT_TICKS(20)), 515 ZTRESS_THREAD(foo_2, user_data_2, 10000, 1000, Z_TIMEOUT_TICKS(20))); 516 517Configuration 518============= 519 520Static configuration of Ztress contains: 521 522 - :kconfig:option:`CONFIG_ZTRESS_MAX_THREADS` - number of supported threads. 523 - :kconfig:option:`CONFIG_ZTRESS_STACK_SIZE` - Stack size of created threads. 524 - :kconfig:option:`CONFIG_ZTRESS_REPORT_PROGRESS_MS` - Test progress report interval. 525 526API reference 527************* 528 529Running tests 530============= 531 532.. doxygengroup:: ztest_test 533 534Assertions 535========== 536 537These macros will instantly fail the test if the related assertion fails. 538When an assertion fails, it will print the current file, line and function, 539alongside a reason for the failure and an optional message. If the config 540:kconfig:option:`CONFIG_ZTEST_ASSERT_VERBOSE` is 0, the assertions will only print the 541file and line numbers, reducing the binary size of the test. 542 543Example output for a failed macro from 544``zassert_equal(buf->ref, 2, "Invalid refcount")``: 545 546.. code-block:: none 547 548 Assertion failed at main.c:62: test_get_single_buffer: Invalid refcount (buf->ref not equal to 2) 549 Aborted at unit test function 550 551.. doxygengroup:: ztest_assert 552 553 554Expectations 555============ 556 557These macros will continue test execution if the related expectation fails and subsequently fail the 558test at the end of its execution. When an expectation fails, it will print the current file, line, 559and function, alongside a reason for the failure and an optional message but continue executing the 560test. If the config :kconfig:option:`CONFIG_ZTEST_ASSERT_VERBOSE` is 0, the expectations will only print the 561file and line numbers, reducing the binary size of the test. 562 563For example, if the following expectations fail: 564 565.. code-block:: C 566 567 zexpect_equal(buf->ref, 2, "Invalid refcount"); 568 zexpect_equal(buf->ref, 1337, "Invalid refcount"); 569 570The output will look something like: 571 572.. code-block:: none 573 574 START - test_get_single_buffer 575 Expectation failed at main.c:62: test_get_single_buffer: Invalid refcount (buf->ref not equal to 2) 576 Expectation failed at main.c:63: test_get_single_buffer: Invalid refcount (buf->ref not equal to 1337) 577 FAIL - test_get_single_buffer in 0.0 seconds 578 579.. doxygengroup:: ztest_expect 580 581Assumptions 582=========== 583 584These macros will instantly skip the test or suite if the related assumption fails. 585When an assumption fails, it will print the current file, line, and function, 586alongside a reason for the failure and an optional message. If the config 587:kconfig:option:`CONFIG_ZTEST_ASSERT_VERBOSE` is 0, the assumptions will only print the 588file and line numbers, reducing the binary size of the test. 589 590Example output for a failed macro from 591``zassume_equal(buf->ref, 2, "Invalid refcount")``: 592 593.. code-block::none 594 595 START - test_get_single_buffer 596 Assumption failed at main.c:62: test_get_single_buffer: Invalid refcount (buf->ref not equal to 2) 597 SKIP - test_get_single_buffer in 0.0 seconds 598 599.. doxygengroup:: ztest_assume 600 601 602Ztress 603====== 604 605.. doxygengroup:: ztest_ztress 606 607 608.. _mocking-fff: 609 610Mocking via FFF 611=============== 612 613Zephyr has integrated with FFF for mocking. See `FFF`_ for documentation. To use it, 614include the relevant header: 615 616.. code-block:: C 617 618 #include <zephyr/fff.h> 619 620Zephyr provides several FFF-based fake drivers which can be used as either stubs or mocks. Fake 621driver instances are configured via :ref:`devicetree` and :ref:`kconfig`. See the following 622devicetree bindings for more information: 623 624 - :dtcompatible:`zephyr,fake-can` 625 - :dtcompatible:`zephyr,fake-eeprom` 626 627Zephyr also has defined extensions to FFF for simplified declarations of fake functions. 628See :ref:`FFF Extensions <fff-extensions>`. 629 630Customizing Test Output 631*********************** 632Customization is enabled by setting :kconfig:option:`CONFIG_ZTEST_TC_UTIL_USER_OVERRIDE` to "y" 633and adding a file :file:`tc_util_user_override.h` with your overrides. 634 635Add the line ``zephyr_include_directories(my_folder)`` to 636your project's :file:`CMakeLists.txt` to let Zephyr find your header file during builds. 637 638See the file :zephyr_file:`subsys/testsuite/include/zephyr/tc_util.h` to see 639which macros and/or defines can be overridden. 640These will be surrounded by blocks such as: 641 642.. code-block:: C 643 644 #ifndef SOMETHING 645 #define SOMETHING <default implementation> 646 #endif /* SOMETHING */ 647 648.. _ztest_shuffle: 649 650Shuffling Test Sequence 651*********************** 652By default the tests are sorted and ran in alphanumerical order. Test cases may 653be dependent on this sequence. Enable :kconfig:option:`CONFIG_ZTEST_SHUFFLE` to 654randomize the order. The output from the test will display the seed for failed 655tests. For native simulator builds you can provide the seed as an argument to 656twister with ``--seed``. 657 658 659Repeating Tests 660*********************** 661By default the tests are executed once. The test cases and test suites 662may be executed multiple times. Enable :kconfig:option:`CONFIG_ZTEST_REPEAT` to 663execute the tests multiple times. By default the multiplication factors are 3, which 664means every test suite is executed 3 times and every test case is executed 3 times. This can 665be changed by the :kconfig:option:`CONFIG_ZTEST_SUITE_REPEAT_COUNT` and 666:kconfig:option:`CONFIG_ZTEST_TEST_REPEAT_COUNT` Kconfig options. 667 668Test Selection 669************** 670For tests built for native simulator, use command line arguments to list 671or select tests to run. The test argument expects a comma separated list 672of ``suite::test`` . You can substitute the test name with an ``*`` to run all 673tests within a suite. 674 675For example 676 677.. code-block:: bash 678 679 $ zephyr.exe -list 680 $ zephyr.exe -test="fixture_tests::test_fixture_pointer,framework_tests::test_assert_mem_equal" 681 $ zephyr.exe -test="framework_tests::*" 682 683 684.. _fff-extensions: 685 686FFF Extensions 687************** 688 689.. doxygengroup:: fff_extensions 690 691 692.. _FFF: https://github.com/meekrosoft/fff 693