Test Framework¶
The Zephyr Test Framework (Ztest) provides a simple testing framework intended to be used during development. It provides basic assertion macros and a generic test structure.
The framework can be used in two ways, either as a generic framework for integration testing, or for unit testing specific modules.
Quick start - Integration testing¶
A simple working base is located at samples/testing/integration. Just copy the files to tests/ and edit them for your needs. The test will then be automatically built and run by the sanitycheck script. If you are testing the bar component of foo, you should copy the sample folder to tests/foo/bar. It can then be tested with ./scripts/sanitycheck -s tests/foo/bar/test.
The sample contains the following files:
Makefile
1 2 3 4 | BOARD ?= qemu_x86
CONF_FILE ?= prj.conf
include $(ZEPHYR_BASE)/Makefile.inc
|
testcase.ini
1 2 | [test]
tags = my_tags
|
prj.conf
1 | CONFIG_ZTEST=y
|
src/Makefile
1 2 3 | obj-y = main.o
include $(ZEPHYR_BASE)/tests/Makefile.test
|
src/main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
static void assert_tests(void)
{
assert_true(1, "1 was false");
assert_false(0, "0 was true");
assert_is_null(NULL, "NULL was not NULL");
assert_not_null("foo", "\"foo\" was NULL");
assert_equal(1, 1, "1 was not equal to 1");
assert_equal_ptr(NULL, NULL, "NULL was not equal to NULL");
}
void test_main(void)
{
ztest_test_suite(framework_tests,
ztest_unit_test(assert_tests)
);
ztest_run_test_suite(framework_tests);
}
|
Quick start - Unit testing¶
Ztest can be used for unit testing. This means that rather than including the entire Zephyr OS for testing a single function, you can focus the testing efforts into the specific module in question. This will speed up testing since only the module will have to be compiled in, and the tested functions will be called directly.
Since you won’t be including basic kernel data structures that most code depends on, you have to provide function stubs in the test. Ztest provides some helpers for mocking functions, as demonstrated below.
In a unit test, mock objects can simulate the behavior of complex real objects and are used to decide whether a test failed or passed by verifying whether an interaction with an object occurred, and if required, to assert the order of that interaction.
The samples/testing/unit folder contains an example for testing the net-buf api of Zephyr.
Makefile
1 2 3 | INCLUDE += subsys
include $(ZEPHYR_BASE)/tests/unit/Makefile.unittest
|
testcase.ini
1 2 3 | [test]
type = unit
tags = buf
|
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | /*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
unsigned int irq_lock(void)
{
return 0;
}
void irq_unlock(unsigned int key)
{
}
#include <net/buf.c>
void k_fifo_init(struct k_fifo *fifo) {}
void k_fifo_put_list(struct k_fifo *fifo, void *head, void *tail) {}
int k_is_in_isr(void)
{
return 0;
}
void *k_fifo_get(struct k_fifo *fifo, int32_t timeout)
{
return NULL;
}
void k_fifo_put(struct k_fifo *fifo, void *data)
{
}
void k_lifo_init(struct k_lifo *lifo) {}
void *k_lifo_get(struct k_lifo *lifo, int32_t timeout)
{
return NULL;
}
void k_lifo_put(struct k_lifo *lifo, void *data)
{
}
#define TEST_BUF_COUNT 1
#define TEST_BUF_SIZE 74
NET_BUF_POOL_DEFINE(bufs_pool, TEST_BUF_COUNT, TEST_BUF_SIZE,
sizeof(int), NULL);
static void test_get_single_buffer(void)
{
struct net_buf *buf;
buf = net_buf_alloc(&bufs_pool, K_NO_WAIT);
assert_equal(buf->ref, 1, "Invalid refcount");
assert_equal(buf->len, 0, "Invalid length");
assert_equal(buf->flags, 0, "Invalid flags");
assert_equal_ptr(buf->frags, NULL, "Frags not NULL");
}
void test_main(void)
{
ztest_test_suite(net_buf_test,
ztest_unit_test(test_get_single_buffer)
);
ztest_run_test_suite(net_buf_test);
}
|
API reference¶
Running tests¶
-
void
ztest_test_fail
(void)¶ Fail the currently running test.
This is the function called from failed assertions and the like. You probably don’t need to call it yourself.
-
static void
unit_test_noop
(void)¶ Do nothing, successfully.
Unit test / setup function / teardown function that does nothing, successfully. Can be used as a parameter to ztest_unit_test_setup_teardown().
-
ztest_unit_test_setup_teardown
(fn, setup, teardown) { \ STRINGIFY(fn), fn, setup, teardown \ }¶ Define a test with setup and teardown functions.
This should be called as an argument to ztest_test_suite. The test will be run in the following order: setup, fn, teardown.
- Parameters
fn
: Main test functionsetup
: Setup functionteardown
: Teardown function
-
ztest_unit_test
(fn) ztest_unit_test_setup_teardown(fn, unit_test_noop, unit_test_noop)¶ Define a test function.
This should be called as an argument to ztest_test_suite.
- Parameters
fn
: Test function
-
ztest_test_suite
(name, ...) struct unit_test _##name[] = { \ __VA_ARGS__, { 0 } \ }¶ Define a test suite.
This function should be called in the following fashion:
ztest_test_suite(test_suite_name, ztest_unit_test(test_function), ztest_unit_test(test_other_function) ); ztest_run_test_suite(test_suite_name);
- Parameters
name
: Name of the testing suite
-
ztest_run_test_suite
(suite) _ztest_run_test_suite(#suite, _##suite)¶ Run the specified test suite.
- Parameters
suite
: Test suite to run.
Assertions¶
These macros will instantly fail the test if the related assertion fails. When an assertion fails, it will print the current file, line and function, alongside a reason for the failure and an optional message. If the config option CONFIG_ZTEST_ASSERT_VERBOSE=0, the assertions will only print the file and line numbers, reducing the binary size of the test.
Example output for a failed macro from assert_equal(buf->ref, 2, “Invalid refcount”):
Assertion failed at main.c:62: test_get_single_buffer: Invalid refcount (buf->ref not equal to 2)
Aborted at unit test function
-
assert
(cond, msg, default_msg) _assert(cond, msg ? msg : "", msg ? ("(" default_msg ")") : (default_msg), \ __FILE__, __LINE__, __func__)¶ Fail the test, if cond is false.
You probably don’t need to call this macro directly. You should instead use assert_{condition} macros below.
- Parameters
cond
: Condition to checkmsg
: Optional, can be NULL. Message to print if cond is false.default_msg
: Message to print if cond is false
-
assert_unreachable
(msg) assert(0, msg, "Reached unreachable code")¶ Assert that this function call won’t be reached.
- Parameters
msg
: Optional message to print if the assertion fails
-
assert_true
(cond, msg) assert(cond, msg, #cond " is false")¶ Assert that cond is true.
- Parameters
cond
: Condition to checkmsg
: Optional message to print if the assertion fails
-
assert_false
(cond, msg) assert(!(cond), msg, #cond " is true")¶ Assert that cond is false.
- Parameters
cond
: Condition to checkmsg
: Optional message to print if the assertion fails
-
assert_is_null
(ptr, msg) assert((ptr) == NULL, msg, #ptr " is not NULL")¶ Assert that ptr is NULL.
- Parameters
ptr
: Pointer to comparemsg
: Optional message to print if the assertion fails
-
assert_not_null
(ptr, msg) assert((ptr) != NULL, msg, #ptr " is NULL")¶ Assert that ptr is not NULL.
- Parameters
ptr
: Pointer to comparemsg
: Optional message to print if the assertion fails
-
assert_equal
(a, b, msg) assert((a) == (b), msg, #a " not equal to " #b)¶ Assert that a equals b.
a and b won’t be converted and will be compared directly.
- Parameters
a
: Value to compareb
: Value to comparemsg
: Optional message to print if the assertion fails
-
assert_not_equal
(a, b, msg) assert((a) != (b), msg, #a " equal to " #b)¶ Assert that a does not equal b.
a and b won’t be converted and will be compared directly.
- Parameters
a
: Value to compareb
: Value to comparemsg
: Optional message to print if the assertion fails
-
assert_equal_ptr
(a, b, msg) assert((void *)(a) == (void *)(b), msg, #a " not equal to " #b)¶ Assert that a equals b.
a and b will be converted to
void *
before comparing.- Parameters
a
: Value to compareb
: Value to comparemsg
: Optional message to print if the assertion fails
Mocking¶
These functions allow abstracting callbacks and related functions and controlling them from specific tests. You can enable the mocking framework by setting CONFIG_ZTEST_MOCKING=y in the configuration file of the test. The amount of concurrent return values and expected parameters is limited by ZTEST_PARAMETER_COUNT.
Here is an example for configuring the function expect_two_parameters to expect the values a=2 and b=3, and telling returns_int to return 5:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <ztest.h>
static void expect_two_parameters(int a, int b)
{
ztest_check_expected_value(a);
ztest_check_expected_value(b);
}
static void parameter_tests(void)
{
ztest_expect_value(expect_two_parameters, a, 2);
ztest_expect_value(expect_two_parameters, b, 3);
expect_two_parameters(2, 3);
}
static int returns_int(void)
{
return ztest_get_return_value();
}
static void return_value_tests(void)
{
ztest_returns_value(returns_int, 5);
assert_equal(returns_int(), 5, NULL);
}
void test_main(void)
{
ztest_test_suite(mock_framework_tests,
ztest_unit_test(parameter_test),
ztest_unit_test(return_value_test)
);
ztest_run_test_suite(mock_framework_tests);
}
|
-
ztest_expect_value
(func, param, value) _ztest_expect_value(STRINGIFY(func), STRINGIFY(param), \ (uintptr_t)(value))¶ Tell function func to expect the value value for param.
When using ztest_check_expected_value(), tell that the value of param should be value. The value will internally be stored as an
uintptr_t
.- Parameters
func
: Function in questionparam
: Parameter for which the value should be setvalue
: Value for param
-
ztest_check_expected_value
(param) _ztest_check_expected_value(__func__, STRINGIFY(param), \ (uintptr_t)(param))¶ If param doesn’t match the value set by ztest_expect_value(), fail the test.
This will first check that does param have a value to be expected, and then checks whether the value of the parameter is equal to the expected value. If either of these checks fail, the current test will fail. This must be called from the called function.
- Parameters
param
: Parameter to check
-
ztest_returns_value
(func, value) _ztest_returns_value(STRINGIFY(func), (uintptr_t)(value))¶ Tell func that it should return value.
- Parameters
func
: Function that should return valuevalue
: Value to return from func
-
ztest_get_return_value
_ztest_get_return_value(__func__)¶ Get the return value for current function.
The return value must have been set previously with ztest_returns_value(). If no return value exists, the current test will fail.
- Return
- The value the current function should return
-
ztest_get_return_value_ptr
((void *)_ztest_get_return_value(__func__))¶ Get the return value as a pointer for current function.
The return value must have been set previously with ztest_returns_value(). If no return value exists, the current test will fail.
- Return
- The value the current function should return as a
void *