pw_unit_test#
GoogleTest for embedded
Stable
#include "mylib.h"
#include "pw_unit_test/framework.h"
namespace {
TEST(MyTestSuite, MyTestCase) {
pw::InlineString<32> expected = "(╯°□°)╯︵ ┻━┻";
pw::InlineString<32> actual = mylib::flip_table();
EXPECT_STREQ(expected.c_str(), actual.c_str());
}
} // namespace
load("@pigweed//pw_unit_test:pw_cc_test.bzl", "pw_cc_test")
cc_library(
name = "mylib",
srcs = ["mylib.cc"],
hdrs = ["mylib.h"],
includes = ["."],
deps = ["@pigweed//pw_string"],
)
pw_cc_test(
name = "mylib_test",
srcs = ["mylib_test.cc"],
deps = [
"@pigweed//pw_unit_test",
":mylib",
],
)
#include "mylib.h"
#include "pw_string/string.h"
namespace mylib {
pw::InlineString<32> flip_table() {
pw::InlineString<32> textmoji = "(╯°□°)╯︵ ┻━┻";
return textmoji;
}
} // namespace mylib
#include "pw_string/string.h"
namespace mylib {
pw::InlineString<32> flip_table();
}
pw_unit_test
provides a GoogleTest-compatible unit testing framework for
Pigweed-based projects. The default backend is a lightweight subset of
GoogleTest that uses embedded-friendly primitives.
Quickstart#
Set up your build system#
Load the pw_cc_test rule and create a target
that depends on @pigweed//pw_unit_test
as well as the code you want
to test:
load("@pigweed//pw_unit_test:pw_cc_test.bzl", "pw_cc_test")
cc_library(
name = "mylib",
srcs = ["mylib.cc"],
hdrs = ["mylib.h"],
includes = ["."],
deps = ["..."],
)
pw_cc_test(
name = "mylib_test",
srcs = ["mylib_test.cc"],
deps = [
"@pigweed//pw_unit_test",
":mylib",
],
)
See also Bazel API reference.
Import $dir_pw_unit_test/test.gni
and create a pw_test
rule that
depends on the code you want to test:
import("$dir_pw_unit_test/test.gni")
pw_source_set("mylib") {
sources = [ "mylib.cc" ]
}
pw_test("mylib_test") {
sources = [ "mylib_test.cc" ]
deps = [ ":mylib" ]
}
See GN reference for more information.
pw_unit_test
generates a simple main
function for running tests on
host. See Create a custom main function to learn how to
create your own main
function for running on-device tests.
Write tests#
Create test suites and test cases:
#include "mylib.h"
#include "pw_unit_test/framework.h"
namespace {
TEST(MyTestSuite, MyTestCase) {
pw::InlineString<32> expected = "(╯°□°)╯︵ ┻━┻";
pw::InlineString<32> actual = app::flip_table();
EXPECT_STREQ(expected.c_str(), actual.c_str());
}
} // namespace
pw_unit_test
provides a standard set of TEST
, EXPECT
, ASSERT
and FAIL
macros. The default backend, pw_unit_test:light
, offers an
embedded-friendly implementation which prioritizes small code size.
Alternativley, users can opt into a larger set of assertion macros, matchers,
and more detailed error messages by using the pw_unit_test:googletest
backend. See Choose a backend.
See GoogleTest Primer for the basics of using GoogleTest.
Run tests#
$ bazel test //src:mylib_test
Run the generated test binary:
$ ./out/.../mylib_test
Guides#
Choose a backend#
The default backend, pw_unit_test:light
, is a lightweight subset of
GoogleTest that uses embedded-friendly primitives. It’s also highly portable
because it offloads the responsibility of test reporting and output to the
underlying system, communicating its results through a common interface. This
lets you write unit tests once and run them under many different environments.
If the subset of GoogleTest that
pw_unit_test:light
supports doesn’t meet your needs, you can access the
full upstream GoogleTest API through pw_unit_test:googletest
. See
Use upstream GoogleTest.
pw_unit_test:light
API compatibility#
pw_unit_test:light
offers a number of primitives for test declaration,
assertion, event handlers, and configuration.
Note
The googletest_test_matchers
target which provides Pigweed-specific
StatusIs
, IsOkAndHolds
isn’t part of the pw_unit_test:light
backend. These matchers are only usable when including the full upstream
GoogleTest backend.
Missing features include:
GoogleMock and matchers (e.g.
EXPECT_THAT
).Death tests (e.g.
EXPECT_DEATH
).EXPECT_DEATH_IF_SUPPORTED
does nothing but silently passes.Value-parameterized tests.
Stream messages (e.g.
EXPECT_TRUE(...) << "My message"
) will compile, but no message will be logged.SCOPED_TRACE will compile, but trace information will not be added to failure messages.
See Use upstream GoogleTest for guidance on using the
upstream GoogleTest backend (pw_unit_test:googletest
) instead of
pw_unit_test:light
.
Create a custom main
function#
For simple unit tests that run on host the workflow outlined in
Quickstart is all you need. Pigweed’s build templates
generate a simple main
function to run the tests with.
To do more complex testing, such as on-device testing:
Create your own
main
function:#include "pw_unit_test/framework.h" // pw_unit_test:light requires an event handler to be configured. #include "pw_unit_test/simple_printing_event_handler.h" void WriteString(std::string_view string, bool newline) { printf("%s", string.data()); if (newline) { printf("\n"); } } int main() { // Make the binary compatible with pw_unit_test:googletest. Has no effect // when using pw_unit_test:light. testing::InitGoogleTest(); // Set up the event handler for pw_unit_test:light. pw::unit_test::SimplePrintingEventHandler handler(WriteString); pw::unit_test::RegisterEventHandler(&handler); return RUN_ALL_TESTS(); }
See Create event handlers for more information about handling events.
Set the build argument that instructs your build system to use your custom
main
function:Bazel:
@pigweed//pw_unit_test:main
Create event handlers#
The pw::unit_test::EventHandler
class defines the interface through which
pw_unit_test:light
communicates the results of its test runs. If you’re
using a custom main function you need to
register an event handler to receive test output from the framework.
Predefined event handlers#
Pigweed provides some standard event handlers to simplify the process of
getting started with pw_unit_test:light
. All event handlers provide for
GoogleTest-style output using the shared
GoogleTestStyleEventHandler base. Example output:
[==========] Running all tests.
[ RUN ] Status.Default
[ OK ] Status.Default
[ RUN ] Status.ConstructWithStatusCode
[ OK ] Status.ConstructWithStatusCode
[ RUN ] Status.AssignFromStatusCode
[ OK ] Status.AssignFromStatusCode
[ RUN ] Status.CompareToStatusCode
[ OK ] Status.CompareToStatusCode
[ RUN ] Status.Ok_OkIsTrue
[ OK ] Status.Ok_OkIsTrue
[ RUN ] Status.NotOk_OkIsFalse
[ OK ] Status.NotOk_OkIsFalse
[ RUN ] Status.KnownString
[ OK ] Status.KnownString
[ RUN ] Status.UnknownString
[ OK ] Status.UnknownString
[==========] Done running all tests.
[ PASSED ] 8 test(s).
Run a subset of test suites#
To run only a subset of registered test suites, use the
pw::unit_test::SetTestSuitesToRun
function. See
pw_unit_test/light_public_overrides/pw_unit_test/framework_backend.h.
This is useful when you’ve got a lot of test suites bundled up into a single test binary and you only need to run some of them.
Skip tests in Bazel#
Use target_compatible_with
in Bazel to skip tests. The following test is
skipped when using upstream GoogleTest:
load("//pw_unit_test:pw_cc_test.bzl", "pw_cc_test")
pw_cc_test(
name = "no_upstream_test",
srcs = ["no_upstream_test.cc"],
target_compatible_with = select({
"//pw_unit_test:backend_is_googletest": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
Run tests in static libraries#
To run tests in a static library, use the PW_UNIT_TEST_LINK_FILE_CONTAINING_TEST macro.
Linkers usually ignore tests through static libraries (i.e. .a
files)
because test registration relies on the test instance’s static constructor
adding itself to a global list of tests. When linking against a static library,
static constructors in an object file are ignored unless at least one entity
in that object file is linked.
Use upstream GoogleTest#
To use the upstream GoogleTest backend (pw_unit_test:googletest
) instead
of the default backend:
Clone the GoogleTest repository into your project. See GoogleTest.
Combine GoogleTestHandlerAdapter with a predefined event handler to enable your
main
function to work with upstream GoogleTest without modification.#include "pw_unit_test/framework.h" #include "pw_unit_test/logging_event_handler.h" int main() { testing::InitGoogleTest(); pw::unit_test::LoggingEventHandler logger; pw::unit_test::RegisterEventHandler(&logger); return RUN_ALL_TESTS(); }
If your tests needs GoogleTest functionality not included in the default
pw_unit_test:light
backend, include the upstream GoogleTest headers (e.g.gtest/gtest.h
) directly and guard your target definition to avoid compiling withpw_unit_test:light
(the default backend).
Run tests over serial#
To accelerate automated unit test bringup for devices with plain-text logging,
pw_unit_test
provides a serial-based test runner in Python that triggers a
device flash and evaluates whether the test passed or failed based on the
produced output.
To set up a serial test runner in Python:
Implement a
SerialTestingDevice
class for your device. See pw_unit_test/py/pw_unit_test/serial_test_runner.py.Configure your device code to wait to run unit tests until
DEFAULT_TEST_START_CHARACTER
is sent over the serial connection.
Run tests over RPC#
pw_unit_test
provides an RPC service which runs unit tests on demand and
streams the results back to the client. The service is defined in
pw_unit_test/pw_unit_test_proto/unit_test.proto.
The RPC service is primarily intended for use with the default
pw_unit_test:light
backend. It has some support for the upstream GoogleTest
backend (pw_unit_test:googletest
), however some features (such as test suite
filtering) are missing.
To set up RPC-based unit tests in your application:
Depend on the relevant target for your build system:
Bazel:
@pigweed//pw_unit_test:rpc_service
GN:
$dir_pw_unit_test:rpc_service
Initialize a
pw::unit_test::UnitTestThread
instance and define apw::Thread
using it as the entry point. (See example below.)Register the thread’s
Service
with your RPC server.#include "pw_rpc/server.h" #include "pw_thread/thread.h" #include "pw_unit_test/unit_test_service.h" pw::rpc::Channel channels[] = { pw::rpc::Channel::Create<1>(&my_output), }; pw::rpc::Server server(channels); constexpr pw::ThreadAttrs kUnitTestThreadAttrs = pw::ThreadAttrs() .set_name("UnitTestThread") .set_priority(pw::ThreadPriority::Medium()) .set_stack_size_bytes(4096); pw::ThreadContextFor<kUnitTestThreadAttrs> unit_test_thread_context; pw::unit_test::UnitTestThread unit_test_thread; void AppInit() { pw::Thread(pw::GetThreadOptions(unit_test_thread_context), unit_test_thread) .detach(); server.RegisterService(unit_test_thread.service()); }
See pw_rpc for more guidance around setting up RPC.
Run tests that have been flashed to a device by calling
pw_unit_test.rpc.run_tests()
in Python. The argument should be an RPC client services object that has the unit testing RPC service enabled. By default, the results output via logging. The return value is aTestRecord
dataclass instance containing the results of the test run.import serial from pw_hdlc import rpc from pw_unit_test.rpc import run_tests PROTO = Path( os.environ['PW_ROOT'], 'pw_unit_test/pw_unit_test_proto/unit_test.proto' ) serial_device = serial.Serial(device, baud) with rpc.SerialReader(serial_device) as reader: with rpc.HdlcRpcClient( reader, PROTO, rpc.default_channels(serial_device.write) ) as client: run_tests(client.rpcs())
Golden file testing with pw_golden_test
#
The pw_golden_test
macro in //pw_unit_test/golden.bzl
defines tests that
execute a binary and compares its output against the contents of a predefined
“golden” file. This is useful for testing that command-line tools or other
binaries run successfully and produce consistent text-based output across code
changes.
If the output of the binary differs from the expected file, the test prints a diff between the actual and expected outputs and exits with a non-zero code.
The following example shows how to use pw_golden_test
in Bazel. The test
runs the //pw_unit_test:run_and_compare_test_executable
C++ binary and
compares its output to the run_and_compare_test.expected
file.
pw_golden_test(
name = "run_and_compare_test",
args = [
"--extra",
"args",
],
executable = "//pw_unit_test:run_and_compare_test_executable",
expected = ":run_and_compare_test.expected",
)
In GN and CMake, directly run the
//pw_unit_test/py/pw_unit_test/golden_test.py
script for golden tests.
C++ API reference#
Moved: pw_unit_test
Python API reference#
pw_unit_test.serial_test_runner
#
Facilitates automating unit tests on devices with serial ports.
This library assumes that the on-device test runner emits the test results
as plain-text over a serial port, and that tests are triggered by a pre-defined
input (DEFAULT_TEST_START_CHARACTER
) over the same serial port that results
are emitted from.
- class pw_unit_test.serial_test_runner.SerialTestingDevice#
A device that supports automated testing via parsing serial output.
- abstract baud_rate() int #
Returns the baud rate to use when connecting to this device.
- Raises:
DeviceNotFound – This device is no longer available.
- abstract load_binary(binary: Path) bool #
Flashes the specified binary to this device.
- Raises:
DeviceNotFound – This device is no longer available.
FlashingFailure – The binary could not be flashed.
- Returns:
True if the binary was loaded successfully.
- abstract serial_port() str #
Returns the name of the com port this device is enumerated on.
- Raises:
DeviceNotFound – This device is no longer available.
- pw_unit_test.serial_test_runner.run_device_test(
- device: ~pw_unit_test.serial_test_runner.SerialTestingDevice,
- binary: ~pathlib.Path,
- test_timeout: float,
- logger: ~logging.Logger = <Logger serial_test_runner (WARNING)>,
Runs tests on a device.
When a unit test run fails, results are logged as an error.
- Parameters:
device – The device to run tests on.
binary – The binary containing tests to flash on the device.
test_timeout – If the device stops producing output longer than this timeout, the test is considered stuck and is aborted.
- Returns:
True if all tests passed.
pw_unit_test.rpc
#
Utilities for running unit tests over pw_rpc.
- class pw_unit_test.rpc.EventHandler#
- abstract run_all_tests_end(passed_tests: int, failed_tests: int) None #
Called after the test run is complete.
- abstract run_all_tests_start() None #
Called before all tests are run.
- abstract test_case_disabled(test_case: TestCase) None #
Called when a disabled test case is encountered.
- abstract test_case_end(test_case: TestCase, result: TestCaseResult) None #
Called when a test case completes with its overall result.
- abstract test_case_expect(test_case: TestCase, expectation: TestExpectation) None #
Called after each expect or assert statement within a test case.
- abstract test_case_start(test_case: TestCase) None #
Called when a new test case is started.
- class pw_unit_test.rpc.TestRecord(
- passing_tests: tuple[TestCase, ...],
- failing_tests: tuple[TestCase, ...],
- disabled_tests: tuple[TestCase, ...],
Records test results.
- __init__(
- passing_tests: tuple[TestCase, ...],
- failing_tests: tuple[TestCase, ...],
- disabled_tests: tuple[TestCase, ...],
- pw_unit_test.rpc.run_tests(
- rpcs: ~pw_rpc.client.Services,
- report_passed_expectations: bool = False,
- test_suites: ~typing.Iterable[str] = (),
- event_handlers: ~typing.Iterable[~pw_unit_test.rpc.EventHandler] = (<pw_unit_test.rpc.LoggingEventHandler object>,
- ),
- timeout_s: ~pw_rpc.callback_client.call.UseDefault | float | None = UseDefault.VALUE,
Runs unit tests on a device over pw_rpc.
Calls each of the provided event handlers as test events occur, and returns
True
if all tests pass.
Build helper libraries#
The following helper libraries can simplify setup and are supported in all build systems.
- simple_printing_event_handler
When running tests, output test results as plain text over
pw_sys_io
.
- simple_printing_main
Implements a
main()
function that simply runs tests using thesimple_printing_event_handler
.
- logging_event_handler
When running tests, log test results as plain text using pw_log. Make sure your target has set a
pw_log
backend.
- logging_main
Implements a
main()
function that simply runs tests using thelogging_event_handler
.
Bazel API reference#
See also Build helper libraries.
pw_cc_test
#
pw_cc_test
is a wrapper for cc_test that provides some defaults, such as
a dependency on @pigweed//pw_unit_test:main
. It supports and passes through
all the arguments recognized by cc_test
.
Label flags#
- @pigweed//pw_unit_test:backend#
The GoogleTest implementation to use for Pigweed unit tests. This library provides
gtest/gtest.h
and related headers. Defaults to@pigweed//pw_unit_test:light
, which implements a subset of GoogleTest.Type: Bazel target label
Usage: Typically specified as part of the platform definition, but can also be set manually on the command line.
- @pigweed//pw_unit_test:main#
Implementation of a main function for
pw_cc_test
unit test binaries. To use upstream GoogleTest, set this to@com_google_googletest//:gtest_main
. Note that this may not work on most embedded devices, see b/310957361.Type: Bazel target label
Usage: Typically specified as part of the platform definition, but can also be set manually on the command line.
GN reference#
See also Build helper libraries.
pw_test
#
pw_test
defines a single unit test suite.
Targets#
- <target_name>
The test suite within a single binary. The test code is linked against the target set in the build arg
pw_unit_test_MAIN
.
- <target_name>.run
If
pw_unit_test_AUTOMATIC_RUNNER
is set, this target runs the test as part of the build.
- <target_name>.lib
The test sources without
pw_unit_test_MAIN
.
Arguments#
All GN executable arguments are accepted and forwarded to the underlying
pw_executable
.
- enable_if#
Boolean indicating whether the test should be built. If false, replaces the test with an empty target. Default true.
- source_gen_deps#
List of target labels that generate source files used by this test. The labels must meet the constraints of GN’s get_target_outputs, namely they must have been previously defined in the current file. This argument is required if a test uses generated source files and
enable_if
can evaluate to false.
- test_main#
Target label to add to the tests’s dependencies to provide the
main()
function. Defaults topw_unit_test_MAIN
. Set to""
ifmain()
is implemented in the test’ssources
.
- test_automatic_runner_args#
Array of args to pass to automatic test runner. Defaults to
pw_unit_test_AUTOMATIC_RUNNER_ARGS
.
- envvars#
Array of
key=value
strings representing environment variables to set when invoking the automatic test runner.
Example#
import("$dir_pw_unit_test/test.gni")
pw_test("large_test") {
sources = [ "large_test.cc" ]
enable_if = device_has_1m_flash
}
pw_test_group
#
pw_test_group
defines a collection of tests or other test groups.
Targets#
- <target_name>
The test group itself.
- <target_name>.run
If
pw_unit_test_AUTOMATIC_RUNNER
is set, this target runs all of the tests in the group and all of its group dependencies individually. See Run tests over serial.
- <target_name>.lib
The sources of all of the tests in this group and their dependencies.
- <target_name>.bundle
All of the tests in the group and its dependencies bundled into a single binary.
- <target_name>.bundle.run
Automatic runner for the test bundle.
Arguments#
- tests#
List of the
pw_test
targets in the group.
- group_deps#
List of other
pw_test_group
targets on which this one depends.
- enable_if#
Boolean indicating whether the group target should be created. If false, an empty GN group is created instead. Default true.
Example#
import("$dir_pw_unit_test/test.gni")
pw_test_group("tests") {
tests = [
":bar_test",
":foo_test",
]
}
pw_test("foo_test") {
# ...
}
pw_test("bar_test") {
# ...
}
pw_facade_test
#
Pigweed facade test templates allow individual unit tests to build under the current device target configuration while overriding specific build arguments. This allows these tests to replace a facade’s backend for the purpose of testing the facade layer.
Facade tests are disabled by default. To build and run facade tests, set the GN
arg pw_unit_test_FACADE_TESTS_ENABLED
to true
.
Warning
Facade tests are costly because each facade test will trigger a re-build of every dependency of the test. While this sounds excessive, it’s the only technically correct way to handle this type of test.
Warning
Some facade test configurations may not be compatible with your target. Be careful when running a facade test on a system that heavily depends on the facade being tested.
GN build arguments#
- pw_unit_test_BACKEND <source_set>#
The GoogleTest implementation to use for Pigweed unit tests. This library provides
gtest/gtest.h
and related headers. Defaults topw_unit_test:light
, which implements a subset of GoogleTest.Type: string (GN path to a source set)
Usage: toolchain-controlled only
- pw_unit_test_MAIN <source_set>#
Implementation of a main function for
pw_test
unit test binaries. See Create a custom main function.Type: string (GN path to a source set)
Usage: toolchain-controlled only
- pw_unit_test_AUTOMATIC_RUNNER <executable>#
Path to a test runner to automatically run unit tests after they are built. See Run tests over serial.
If set, a
pw_test
target’s<target_name>.run
action invokes the test runner specified by this argument, passing the path to the unit test to run. If this is unset, thepw_test
target’s<target_name>.run
step will do nothing.Targets that don’t support parallelized execution of tests (e.g. an on-device test runner that must flash a device and run the test in serial) should set
pw_unit_test_POOL_DEPTH
to1
.Type: string (name of an executable on
PATH
, or a path to an executable)Usage: toolchain-controlled only
- pw_unit_test_AUTOMATIC_RUNNER_ARGS <args>#
An optional list of strings to pass as args to the test runner specified by
pw_unit_test_AUTOMATIC_RUNNER
.Type: list of strings (args to pass to
pw_unit_test_AUTOMATIC_RUNNER
)Usage: toolchain-controlled only
- pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT <timeout_seconds>#
An optional timeout to apply when running the automatic runner. Timeout is in seconds. Defaults to empty which means no timeout.
Type: string (number of seconds to wait before killing test runner)
Usage: toolchain-controlled only
- pw_unit_test_POOL_DEPTH <pool_depth>#
The maximum number of unit tests that may be run concurrently for the current toolchain. Setting this to 0 disables usage of a pool, allowing unlimited parallelization.
Note: A single target with two toolchain configurations (e.g.
release
anddebug
) uses two separate test runner pools by default. Setpw_unit_test_POOL_TOOLCHAIN
to the same toolchain for both targets to merge the pools and force serialization.Type: integer
Usage: toolchain-controlled only
- pw_unit_test_POOL_TOOLCHAIN <toolchain>#
The toolchain to use when referring to the
pw_unit_test
runner pool. When this is disabled, the current toolchain is used. This means that every toolchain will use its own pool definition. If two toolchains should share the same pool, this argument should be by one of the toolchains to the GN path of the other toolchain.Type: string (GN path to a toolchain)
Usage: toolchain-controlled only
- pw_unit_test_EXECUTABLE_TARGET_TYPE <template name>#
The name of the GN target type used to build
pw_unit_test
executables.Type: string (name of a GN template)
Usage: toolchain-controlled only
- pw_unit_test_EXECUTABLE_TARGET_TYPE_FILE <gni file path>#
The path to the
.gni
file that definespw_unit_test_EXECUTABLE_TARGET_TYPE
.If
pw_unit_test_EXECUTABLE_TARGET_TYPE
is not the default ofpw_executable
, this.gni
file is imported to provide the template definition.Type: string (path to a .gni file)
Usage: toolchain-controlled only
- pw_unit_test_FACADE_TESTS_ENABLED <boolean>#
Controls whether to build and run facade tests. Facade tests add considerably to build time, so they are disabled by default.
- pw_unit_test_TESTONLY <boolean>#
Controls the
testonly
variable inpw_test
,pw_test_group
, and miscellaneous testing targets. This is useful if your test libraries (e.g. GoogleTest) used by pw_unit_test have thetestonly
flag set. False by default for backwards compatibility.
CMake reference#
See also Build helper libraries.
pw_add_test
#
pw_add_test
declares a single unit test suite.
Tip
Upstream Pigweed tests can be disabled in downstream projects by setting
pw_unit_test_ENABLE_PW_ADD_TEST
to OFF
before adding the pigweed
directory to an existing cmake build.
set(pw_unit_test_ENABLE_PW_ADD_TEST OFF)
add_subdirectory(path/to/pigweed pigweed)
set(pw_unit_test_ENABLE_PW_ADD_TEST ON)
See also: Use Pigweed from an existing CMake project.
Targets#
- {NAME}
Depends on
${NAME}.run
ifpw_unit_test_AUTOMATIC_RUNNER
is set, else it depends on${NAME}.bin
.
- {NAME}.lib
Contains the provided test sources as a library target, which can then be linked into a test executable.
- {NAME}.bin
A standalone executable which contains only the test sources specified in the
pw_unit_test
template.
- {NAME}.run
Runs the unit test executable after building it if
pw_unit_test_AUTOMATIC_RUNNER
is set, else it fails to build.
Required arguments#
- NAME#
Name to use for the produced test targets specified above.
Optional arguments#
- SOURCES#
Source files for this library.
- HEADERS#
Header files for this library.
- PRIVATE_DEPS#
Private
pw_target_link_targets
arguments.
- PRIVATE_INCLUDES#
Public
target_include_directories
argument.
- PRIVATE_DEFINES#
Private
target_compile_definitions
arguments.
- PRIVATE_COMPILE_OPTIONS#
Private
target_compile_options
arguments.
- PRIVATE_LINK_OPTIONS#
Private
target_link_options
arguments.
Example#
include($ENV{PW_ROOT}/pw_unit_test/test.cmake)
pw_add_test(my_module.foo_test
SOURCES
foo_test.cc
PRIVATE_DEPS
my_module.foo
)
pw_add_test_group
#
pw_add_test_group
defines a collection of tests or other test groups.
Targets#
- {NAME}
Depends on
${NAME}.run
ifpw_unit_test_AUTOMATIC_RUNNER
is set, else it depends on${NAME}.bin
.
- {NAME}.bundle
Depends on
${NAME}.bundle.run
ifpw_unit_test_AUTOMATIC_RUNNER
is set, else it depends on${NAME}.bundle.bin
.
- {NAME}.lib
Depends on
${NAME}.bundle.lib
.
- {NAME}.bin
Depends on the provided
TESTS
’s<test_dep>.bin
targets.
- {NAME}.run
Depends on the provided
TESTS
’s<test_dep>.run
targets ifpw_unit_test_AUTOMATIC_RUNNER
is set, else it fails to build.
- {NAME}.bundle.lib
Contains the provided tests bundled as a library target, which can then be linked into a test executable.
- {NAME}.bundle.bin
Standalone executable which contains the bundled tests.
- {NAME}.bundle.run
Runs the
{NAME}.bundle.bin
test bundle executable after building it ifpw_unit_test_AUTOMATIC_RUNNER
is set, else it fails to build.
Required arguments#
- NAME#
The name of the executable target to be created.
- TESTS#
pw_add_test
targets andpw_add_test_group
bundles to be included in this test bundle.
Example#
include($ENV{PW_ROOT}/pw_unit_test/test.cmake)
pw_add_test_group(tests
TESTS
bar_test
foo_test
)
pw_add_test(foo_test
# ...
)
pw_add_test(bar_test
# ...
)
CMake build arguments#
- pw_unit_test_BACKEND <target>#
The GoogleTest implementation to use for Pigweed unit tests. This library provides
gtest/gtest.h
and related headers. Defaults topw_unit_test.light
, which implements a subset of GoogleTest.Type: string (CMake target name)
Usage: toolchain-controlled only
- pw_unit_test_AUTOMATIC_RUNNER <executable>#
Path to a test runner to automatically run unit tests after they’re built.
If set, a
pw_test
target’s${NAME}
and${NAME}.run
targets will invoke the test runner specified by this argument, passing the path to the unit test to run. If this is unset, thepw_test
target’s${NAME}
will only build the unit test(s) and${NAME}.run
will fail to build.Type: string (name of an executable on the PATH, or path to an executable)
Usage: toolchain-controlled only
- pw_unit_test_AUTOMATIC_RUNNER_ARGS <args>#
An optional list of strings to pass as args to the test runner specified by
pw_unit_test_AUTOMATIC_RUNNER
.Type: list of strings (args to pass to pw_unit_test_AUTOMATIC_RUNNER)
Usage: toolchain-controlled only
- pw_unit_test_AUTOMATIC_RUNNER_TIMEOUT_SECONDS <timeout_seconds>#
An optional timeout to apply when running the automatic runner. Timeout is in seconds. Defaults to empty which means no timeout.
Type: string (number of seconds to wait before killing test runner)
Usage: toolchain-controlled only
- pw_unit_test_ADD_EXECUTABLE_FUNCTION <function name>#
The name of the CMake function used to build
pw_unit_test
executables. The provided function must take aNAME
and aTEST_LIB
argument which are the expected name of the executable target and the target which provides the unit test(s).Type: string (name of a CMake function)
Usage: toolchain-controlled only
- pw_unit_test_ADD_EXECUTABLE_FUNCTION_FILE <cmake file path>#
The path to the
.cmake
file that definespw_unit_test_ADD_EXECUTABLE_FUNCTION
.Type: string (path to a
.cmake
file)Usage: toolchain-controlled only
Zephyr backend tests#
Zephyr backend tests use Zephyr’s test runner twister. The test runner is
installed into the Pigweed CLI and can be run by calling pw twister-runner
.
The runner intercepts a few arguments in order to add features to the normal
test runner; beyond that, the runner just calls twister directly.
The runner will intercept the -T
or --testsuite-root
arguments and do
the following:
For every
testcase.yaml
file under the testsuite root directory it appends-T path/to/testcase.yaml
.For every
testtemplate.yaml
it creates a new directory using the{name}
field in the YAML file and the--build-dir
to create a new test root at{build_dir}/{name}
. It will then take thetestcase
node in the template and create a new{build_dir}/{name}/testcase.yaml
. This new YAML file will be appended to the final twister command using-T {build_dir}/{name}
.
Test templates#
Twister normally uses a combination of testcase.yaml
files along
CMakeLists.txt
files which serve as the test’s entry point. This doesn’t
work when trying to write tests side by side with the source. The twister runner
introduces the concept of testtemplate.yaml
which allows the test to live in
the same directory as the source but is compatible with twister. The test
template YAML file contains the following required keys:
name
- The name of the test directory to create. This must be unique per twister run.testcase
- The content of this entry will be copied into a new{build_dir}/{name}/testcase.yaml
file.
Additional fields are available in the template and are optional:
file-map
- This key/value dictionary contains a mapping of relative file paths (reltive to thetesttemplate.yaml
file) to output relative file paths (relative to the generated{build_dir}/{name)
). Each entry will create a symlink.use-default-cmake
- By defaulttrue
and allows the test to leverage a commonCMakeLists.txt
that should fit the majority of test cases. It sets up a simple Zephyr app which uses thesimple_printing_main.cc
to run the tests. ThisCMake
file also expects that the test will be a library created bypw_add_test
. For example, if we wanted to test thepw_base64.base64_test
unit test we would just need to passTEST_LIB=pw_base64.base64_test
as aCMake
argument.use-default-prj-conf
- By defaulttrue
and allows the test to leverage a commonprj.conf
that should fit the majority of test cases. It sets up C++20 and a few other common Kconfigs. Additional configs can be added as a part of thetesttemplate.yaml
using theextra_configs
key.
Running the tests#
Automatically, tests will be picked up by pw presubmit --step zephyr_build
.
This presubmit test will call the twister-runner
script to run all the tests
defined in either testcase.yaml
or testtemplate.yaml
. Coverage reports
can be found later in twister-out/coverage/
.