组件测试

借助 Fuchsia 测试运行程序框架,开发者能够使用各种语言和运行时为组件构建测试,并在目标设备上执行这些测试。该框架提供了测试运行程序组件,可实现 fuchsia.test.Suite 协议并与通用语言专用测试框架(例如 GoogleTest (C++))集成。

test_manager 组件负责在 Fuchsia 设备上运行测试。它会检查实现测试套件协议的组件,并将其作为子组件启动。这意味着,test_manager 还负责为每个测试套件提供功能,从而创建通常所谓的“测试领域”。

示意图:测试运行程序框架如何为开发者提供用于公开测试套件的接口,以及让开发者工具在 Fuchsia 设备上执行测试。

开发者工具(如 ffx test)会与设备上的 test_manager 通信,以执行测试套件并检索结果。

测试运行程序

测试运行程序是测试运行程序框架与开发者用于以其首选语言编写测试的通用框架之间的可重复使用适配器。每个测试运行程序组件都会公开 fuchsia.test.Suite 功能,以便 test_manager 枚举和执行各个测试,并声明支持测试框架的适当执行 runner

Rust

{
    // Execute tests using language-specific runner
    program: { runner: "rust_test_runner" },
    // Expose test suite protocol to test manager
    capabilities: [
        { protocol: "fuchsia.test.Suite" },
    ],
    expose: [
        {
            protocol: "fuchsia.test.Suite",
            from: "self",
        },
    ],
}

C++

{
    // Execute tests using language-specific runner
    program: { runner: "gtest_runner" },
    // Expose test suite protocol to test manager
    capabilities: [
        { protocol: "fuchsia.test.Suite" },
    ],
    expose: [
        {
            protocol: "fuchsia.test.Suite",
            from: "self",
        },
    ],
}

为了简化集成,测试运行程序框架为每个特定于语言的运行程序提供了清单分片。下面是一个等效的测试运行程序 CML,用于声明前面示例组件测试中的功能。

Rust

{
    include: [ "//src/sys/test_runners/rust/default.shard.cml" ]
}

C++

{
    include: [ "//src/sys/test_runners/gtest/default.shard.cml" ]
}

单元测试

单元测试侧重于验证组件中的各个代码单元,并与系统上的其他组件隔离开来。单元测试应该是封闭测试,也就是说,它们不需要测试,也不需要提供测试之外的其他功能。

Fuchsia 构建系统提供其他 GN 目标,以协助单元测试组件:

  • fuchsia_unittest_package():此单组件软件包会自动生成引用测试二进制文件的最基本组件清单,无需额外的功能。
  • fuchsia_unittest_component():可生成相同的最小组件清单的组件声明。如果您需要将多个单元测试组件构建到同一 fuchsia_package() 中,此规则非常有用。

以下是用于添加单元测试的 BUILD.gn 代码段示例:

import("//build/components.gni")

executable("bin_test") {
  sources = [ "main_test.cc" ]
  deps = [
    "//src/lib/fxl/test:gtest_main",
    "//third_party/googletest:gtest",
  ]
  testonly = true
}

fuchsia_unittest_package("hello-world-unittests") {
  deps = [
    ":bin_test",
  ]
}

练习:Echo 单元测试

在本练习中,您将使用测试运行程序框架向 echo-args 组件添加单元测试,并在 FEMU 环境中运行这些测试。

实现单元测试

单元测试可验证组件的内部函数是否按预期运行。对于 echo-args 组件,您将验证上一个练习中使用的 greeting() 函数是否返回预期值。

添加以下单元测试函数,以验证 greeting() 函数在提供一个、两个或三个参数时的行为:

Rust

echo-args/src/main.rs

#[cfg(test)]
mod tests {
    #[fuchsia::test]
    async fn test_greet_one() {
        let names = vec![String::from("Alice")];
        let expected = "Alice";
        assert_eq!(super::greeting(&names), expected);
    }

    #[fuchsia::test]
    async fn test_greet_two() {
        let names = vec![String::from("Alice"), String::from("Bob")];
        let expected = "Alice and Bob";
        assert_eq!(super::greeting(&names), expected);
    }

    #[fuchsia::test]
    async fn test_greet_three() {
        let names = vec![String::from("Alice"), String::from("Bob"), String::from("Spot")];
        let expected = "Alice, Bob, Spot";
        assert_eq!(super::greeting(&names), expected);
    }
}

C++

echo-args/echo_unittest.cc

#include <gtest/gtest.h>

#include "vendor/fuchsia-codelab/echo-args/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);
}

更新 build 配置

将以下规则添加到 BUILD.gn 文件中,以生成新的单元测试软件包:

Rust

echo-args/BUILD.gn

group("tests") {
  testonly = true
  deps = [ ":echo-args-unittests" ]
}

fuchsia_unittest_package("echo-args-unittests") {
  deps = [ ":bin_test" ]
}

C++

echo-args/BUILD.gn

group("tests") {
  testonly = true
  deps = [ ":echo-args-unittests" ]
}

executable("unittests") {
  output_name = "echo-args-test"
  testonly = true

  sources = [ "echo_unittest.cc" ]

  deps = [
    ":cpp-lib",
    "//src/lib/fxl/test:gtest_main",
    "//third_party/googletest:gtest",
  ]
}

fuchsia_unittest_package("echo-args-unittests") {
  deps = [ ":unittests" ]
}

此规则将您的单元测试打包到以下网址的组件中:

fuchsia-pkg://fuchsia.com/echo-args-unittests#meta/echo-args-unittests.cm

运行单元测试

更新顶级构建目标,以同时构建组件软件包和测试软件包:

Rust

echo-args/BUILD.gn

import("//build/components.gni")
import("//build/rust/rustc_binary.gni")


group("echo-args") {
  testonly = true
  deps = [
    ":package",
    ":tests",
  ]
}

C++

echo-args/BUILD.gn

import("//build/components.gni")


group("echo-args") {
  testonly = true
  deps = [
    ":package",
    ":tests",
  ]
}

再次运行 fx build 以构建测试软件包:

fx build

使用 ffx test 命令执行此软件包中的单元测试。 验证测试是否通过:

ffx test run \
    fuchsia-pkg://fuchsia.com/echo-args-unittests#meta/echo-args-unittests.cm