The µTest++ Testing Framework Frequently Asked Questions
Why are the actual values not shown when a check fails?
Because the check is a plain bool expression. In
t.expect (compute_answer () == 42), the comparison is evaluated before
expect() is called, so µTest++ receives only false, and can report
only the file and the line.
To have the values reported, use a function comparator, so that the comparison is performed by µTest++:
t.expect (mt::eq (compute_answer (), 42)) << "answer is 42";
A failure then also reports the operands, for example
condition: "43 == 42".
What happens when a requirement fails?
The failure is reported like a failed expectation, marked by the human-readable
reporter with the effect that follows, and then, when exceptions are
enabled, the current test case is
stopped: the rest of its body is skipped, and the run continues with
the next test case. This is how the fatal assertions of most other
frameworks behave (ASSERT_* in GoogleTest, REQUIRE() in Catch2 and
doctest, BOOST_REQUIRE() in Boost.Test); see the comparison in the
User's Guide.
Without exceptions, the test case cannot be stopped alone, so the
whole test execution is aborted. The results of the test case,
ending with the failed requirement, are first displayed after its name
(also with --quiet, but then only the failed checks, and not with
--silent) and written to the output file, followed, in place of the
totals, by a line with the
location of the failure (✗ Test execution aborted at <file>:<line>
with the human-readable reporter, Bail out! Requirement failed at <file>:<line> with the TAP reporter). Then runner::abort() calls the
handler set with runner::set_abort_handler(), if any, and then
abort(). The remaining test cases and suites do not run, and no final
totals are written; see
Aborting the test execution.
Use require() only for conditions without which the following checks
are meaningless, and expect() for everything else.
How can the test results be written to a file?
Use the --output-file option, either as --output-file=<path> or as
--output-file <path>. The file is intended for the integration with
other tools, while the console is intended for the people who watch the
tests run. With both reporters, the file receives the complete
results, whatever the console verbosity selected with --verbose,
--quiet, or --silent. The TAP reporter (the default) writes a valid
TAP document, so, for integration, use it. If the path is
missing or the file cannot be created, the error is reported on
stderr and on the console, no test is run, and the program returns 2.
On embedded platforms, the file is created with fopen(), so the
platform must support file operations, for example through
semihosting.
What does --quiet show?
The failed checks, with their locations and the names of the suite and
of the test cases that contain them, and the totals. With the TAP
reporter, it also displays one ok/not ok line per test suite, and
writes the failed checks as comments, so that the console output remains
a valid TAP document. The passed checks and the passed test cases are
not displayed; they are available in the output file, which always
receives every check, whatever the verbosity:
sample-test --quiet --output-file=sample-test.tap
See Verbosity.
How can the human-readable output be selected?
Use --reporter=human or --reporter human. The default is
--reporter=tap, which produces TAP 14 output. Any other name is
rejected with error: unknown reporter '<name>', and no test is run.
Why is the human-readable output not coloured in CI?
By default, the human-readable reporter uses colours only when stdout is a
terminal, which is not the case in most CI systems, or when the output is piped.
To force them, for example when the CI log renders the ANSI escape sequences,
use --colour (or --colour=always); to disable them, use --colour=never
(the value must be attached with =; a separate --colour never is reported as
an error). The American spelling --color, and the Catch2 and Boost UT form,
--use-colour=yes or --use-colour=no (also spelled --use-color), is also
accepted. The output file never receives colours. See
Colours.
Why do my static test suites not run?
Usually because the source files that define them are compiled into a static library. The linker includes an object file from a static library only when the program references one of its symbols, and nothing references a static suite: it registers itself from its constructor. The object file is therefore dropped, and the suite silently does not run.
Link the files that define static suites as object files: add them
directly to the executable, use a CMake OBJECT library, or wrap the
library in -Wl,--whole-archive … -Wl,--no-whole-archive.
Why is the test output out of order on my board?
The reporters write through stdout (vfprintf(), fwrite(), and fflush()).
If the platform forwards only printf() to the host, for example with
-Wl,--wrap=printf, and stdout goes elsewhere, the two streams are not
synchronised. Route stdout and all the printf() family to the same
destination. See the Console
output section of the User's
Guide.
How can the output be sent to a serial port or RTT?
By retargeting the C library; µTest++ has no output hook of its own. The
reporters write through stdout, the errors through stderr, and the output
file through fopen(), so whatever the C library does with them applies to the
test output as well. On the µOS++ platforms, all of them are forwarded to the
host through semihosting, which requires a debugger or QEMU. In other
environments, implement the C library back end (for example _write() with
newlib) for the desired channel. See the Console
output section of the User's
Guide.
Can µTest++ be used to test C code?
Yes. The code under test can be written in C, but the tests themselves
are written in C++20, since µTest++ relies on C++ features that have no
C equivalent. Include the C headers in the C++ test sources, within
extern "C" if they do not already provide it.
In what order do the tests run?
The test cases added to the top suite in main(), with ts.test (…),
run immediately, in the order of the calls. The suites added with
add_suite() and the static suites run later, when run_suites() is called,
together, sorted by name; for equal names, they run in the order of
their creation, so the static suites, constructed before main(), run
before the suites added with add_suite().
The names are compared byte by byte, as with strcmp(), not in the
order of registration and not alphabetically: the comparison is
case-sensitive, so "Zeta" runs before "alpha", and the digits are
compared one at a time, so "Suite 10" runs before "Suite 2". To
run the suites in a given order, start their names with zero-padded
numbers ("01 - Init", "02 - Run"), and use the same case.
The test cases within a suite run in the order in which they are defined.