The Fuchsia Test Runner Framework enables developers to build tests for
components using a variety of languages and runtimes and execute them on a
target device. The framework provides test runner components that implement
the fuchsia.test.Suite
protocol and integrate with common language-specific
testing frameworks such as GoogleTest (C++).
The test_manager
component is responsible for running tests on a Fuchsia
device. It examines components implementing the test suite protocol and launches
them as child components. This means that test_manager
is also responsible for
providing capabilities to each test suite, creating what is commonly called the
test realm.
Developer tools such as ffx test
communicate with the test_manager
on the
device to execute test suites and retrieve the results.
Test runners
Test runners are reusable adapters between the Test Runner Framework and common
frameworks used by developers to write tests in their preferred language.
Each test runner component exposes the fuchsia.test.Suite
capability that
enables the test_manager
to enumerate and execute individual tests, and
declares the appropriate execution runner
with test framework support.
{
// Execute tests using language-specific runner
program: { runner: "elf_test_runner", },
// Expose test suite protocol to test manager
capabilities: [
{ protocol: "fuchsia.test.Suite" },
],
expose: [
{
protocol: "fuchsia.test.Suite",
from: "self",
},
],
}
To simplify integration, the Test Runner Framework provides manifest shards for each language-specific runner. The following is an equivalent test runner CML for declaring the capabilities from the previous example component tests.
{
include: [ "sys/testing/elf_test_runner.shard.cml" ]
}
Unit tests
Unit testing focuses on validating the individual units of code within your component and isolated from other components on the system. Unit tests should be hermetic, meaning that they do not require or provide additional capabilities outside of the test.
The Fuchsia SDK provides additional templates to facilitate the creation of unit test components:
fuchsia_cc_test()
: Compiles the C++ source code into a test binary. When added to a package, this rule also generates a minimal component manifest that references the test binary and requires no additional capabilities.fuchsia_test_package()
: Generates a Fuchsia package containing one or more test components and their dependencies.
Below is an example BUILD.bazel
snippet for including unit tests:
load(
"fuchsia_cc_test",
"fuchsia_select",
"fuchsia_test_package",
)
fuchsia_cc_test(
name = "hello_world_test",
srcs = ["hello_world_test.cc"],
deps = fuchsia_select({
"@platforms//os:fuchsia": [
"@fuchsia_sdk//pkg/fdio",
"@fuchsia_sdk//pkg/syslog",
],
}),
)
fuchsia_test_package(
name = "unit_test_pkg",
visibility = ["//visibility:public"],
deps = [
":hello_world_test",
],
)
Exercise: Echo unit tests
In this exercise, you'll add unit tests to the echo
component with the
Test Runner Framework and run those tests in a FEMU environment.
After you complete this section, the project should have the following directory structure:
//fuchsia-codelab/echo
|- BUILD.bazel
|- meta
| |- echo.cml
|
|- echo_component.cc
|- echo_component.h
|- echo_unittest.cc
|- main.cc
echo_unittest.cc
: Source code for the C++ unit tests.
Implement unit tests
Unit tests verify that the internal functions of the component behave as
expected. For the echo
component, you'll validate that the greeting()
function used in the previous exercise returns the expected values.
Create echo/echo_unittest.cc
and add the following unit test functions to
validate the behavior of the greeting()
function when supplied with one, two,
or three arguments:
echo/echo_unittest.cc
:
#include <gtest/gtest.h>
#include "echo_component.h"
TEST(EchoTest, TestGreetOne) {
std::vector<std::string> names = {"Alice"};
std::string expected = "Alice";
ASSERT_TRUE(echo::greeting(names) == expected);
}
TEST(EchoTest, TestGreetTwo) {
std::vector<std::string> names = {"Alice", "Bob"};
std::string expected = "Alice and Bob";
ASSERT_TRUE(echo::greeting(names) == expected);
}
TEST(EchoTest, TestGreetThree) {
std::vector<std::string> names = {"Alice", "Bob", "Spot"};
std::string expected = "Alice, Bob, Spot";
ASSERT_TRUE(echo::greeting(names) == expected);
}
Run the unit tests
Update the imports section of your echo/BUILD.bazel
file to include the
additional test rules:
echo/BUILD.bazel
:
load(
"@fuchsia_sdk//fuchsia:defs.bzl",
"fuchsia_cc_binary",
"fuchsia_cc_test",
"fuchsia_component",
"fuchsia_component_manifest",
"fuchsia_package",
"fuchsia_select",
"fuchsia_unittest_package",
)
Add the following build rules to include your tests in the build configuration:
echo/BUILD.bazel
:
fuchsia_cc_test(
name = "echo_unittests",
size = "small",
srcs = [
"echo_component.cc",
"echo_component.h",
"echo_unittest.cc",
],
visibility = ["//visibility:public"],
deps = ["@com_google_googletest//:gtest_main"] + fuchsia_select({
"@platforms//os:fuchsia": [
"@fuchsia_sdk//pkg/fdio",
"@fuchsia_sdk//pkg/syslog",
],
}),
)
fuchsia_unittest_package(
name = "test_pkg",
package_name = "echo_unittests",
visibility = ["//visibility:public"],
unit_tests = [
":echo_unittests",
],
)
This rule packages your unit tests into a component with the following URL:
fuchsia-pkg://fuchsiasamples.com/echo_unittests#meta/echo_unittests.cm
Build and publish the test package to the fuchsiasamples.com
repository:
bazel run //fuchsia-codelab/echo:test_pkg.publish -- \
--repo_name fuchsiasamples.com
Use the ffx test
command to execute the unit tests inside this package.
Verify that the tests pass:
ffx test run \
fuchsia-pkg://fuchsiasamples.com/echo_unittests#meta/echo_unittests.cm