整合測試拓撲

整合測試情境包含兩個以上元件,這些元件在同一領域執行和交換功能。雖然大多數測試都是橫跨單一元件的單元測試,但整合測試情境呼叫要定義領域拓撲和能力路徑。

測試 Runner Framework 整合

整合測試元件與 Test Runner Framework 整合了符合支援語言特定測試架構的測試執行器資料分割。

Rust

include: [
    "//src/sys/test_runners/rust/default.shard.cml",
    "syslog/client.shard.cml",
],

// Information about the program to run.
program: {
    // The binary to run for this component.
    binary: "bin/echo_integration_test_rust",
},

C++

include: [
    "//src/sys/test_runners/gtest/default.shard.cml",
    "syslog/client.shard.cml",
],

// Information about the program to run.
program: {
    // The binary to run for this component.
    binary: "bin/echo_integration_test_cpp",
},

這個資料分割提供兩個主要元素:

  1. 公開 fuchsia.test.Suite 通訊協定,供架構探索及執行測試案例。
  2. 將程式 runner 設為提供的測試架構提供的測試執行元件。

測試領域拓撲

整合測試元件會以本身做為父項,宣告測試領域的拓撲。如此一來,測試控制器就能負責測試受測試元件及其依附元件之間的能力轉送。

以下是 echo_server 元件的整合測試範例:


整合測試拓撲

這個簡單的測試領域會繫結至 echo_server 元件公開的 fidl.examples.routing.echo.Echo 通訊協定。echo_integration_test 套件包含下列元件:

  • echo_integration_test - 測試控制器元件
  • echo_server - 測試中的元件

您可以透過下列方式定義測試領域拓撲:

請參閱下表,找出最適合整合測試的做法:

整合測試案例 運作範圍建構工具 靜態 CML
使用靜態依附元件進行簡單的整合測試
每個測試案例的不重複元件執行個體
與各個測試案例繫結的測試元件生命週期
針對受測元件的動態假、模擬和虛設常式執行個體
測試案例之間的動態轉送與設定

運作範圍建構工具

如果必須在執行階段定義領域拓撲,或是需要以本機模擬實作取代元件,您可以使用 Realm Builder 程式庫,在測試程式碼中動態建立拓撲。

測試控制器元件的資訊清單包含使用實際元件資訊清單資料分割的 Realm Builder 程式庫:

Rust

include: [
    "sys/component/realm_builder.shard.cml",
    // ...
],

C++

include: [
    "sys/component/realm_builder.shard.cml",
    // ...
],

測試控制器程式碼會建構測試領域拓撲,將 echo_server 新增為子項元件,並宣告必要的能力路徑傳回父項:

Rust

use {
    // ...
    fuchsia_component_test::{
        Capability, ChildOptions, LocalComponentHandles, RealmBuilder, Ref, Route,
    },
    futures::{StreamExt, TryStreamExt},
};

// ...

let builder = RealmBuilder::new().await?;

// Add component to the realm, which is fetched using a URL.
let echo_server = builder
    .add_child(
        "echo_server",
        "fuchsia-pkg://fuchsia.com/realm-builder-examples#meta/echo_server.cm",
        ChildOptions::new(),
    )
    .await?;

builder
    .add_route(
        Route::new()
            .capability(Capability::protocol_by_name("fidl.examples.routing.echo.Echo"))
            .from(&echo_server)
            .to(Ref::parent()),
    )
    .await?;

C++

#include <lib/sys/component/cpp/testing/realm_builder.h>

// ...

auto builder = RealmBuilder::Create();

// Add component server to the realm, which is fetched using a URL.
builder.AddChild("echo_server",
                 "fuchsia-pkg://fuchsia.com/realm-builder-examples#meta/echo_server.cm");

builder.AddRoute(Route{.capabilities = {Protocol{"fidl.examples.routing.echo.Echo"}},
                       .source = ChildRef{"echo_server"},
                       .targets = {ParentRef()}});

測試控制器程式碼會透過已建立的領域公開的功能與 echo_server 互動:

Rust

let realm = builder.build().await?;

let echo = realm.root.connect_to_protocol_at_exposed_dir::<fecho::EchoMarker>()?;
assert_eq!(echo.echo_string(Some("hello")).await?, Some("hello".to_owned()));

C++

auto realm = builder.Build(dispatcher());

auto echo = realm.component().ConnectSync<fidl::examples::routing::echo::Echo>();
fidl::StringPtr response;
echo->EchoString("hello", &response);
ASSERT_EQ(response, "hello");

如需使用 Realm Builder 實作測試的完整詳細資訊,請參閱 Realm Builder 開發人員指南。

元件資訊清單

如果測試中的所有元件都是靜態的,您可以在測試控制器的元件資訊清單中,使用 CML 以宣告方式定義測試領域的整個拓撲。

測試控制器元件的資訊清單會將受測試的 echo_server 元件靜態宣告為子項,並將必要功能轉送至父項:

Rust

{
    include: [
        "//src/sys/test_runners/rust/default.shard.cml",
        "syslog/client.shard.cml",
    ],

    // Information about the program to run.
    program: {
        // The binary to run for this component.
        binary: "bin/echo_integration_test_rust",
    },


    // Child components orchestrated by the integration test.
    children: [
        {
            name: "echo_server",
            url: "#meta/echo_server.cm",
        },
    ],

    // Capabilities used by this component.
    use: [
        {
            protocol: [ "fidl.examples.routing.echo.Echo" ],
            from: "#echo_server",
        },
    ],

    // Capabilities required by components under test.
    offer: [
        {
            protocol: [
                "fuchsia.inspect.InspectSink",
                "fuchsia.logger.LogSink",
            ],
            from: "parent",
            to: "#echo_server",
        },
    ],
}

C++

{
    include: [
        "//src/sys/test_runners/gtest/default.shard.cml",
        "syslog/client.shard.cml",
    ],

    // Information about the program to run.
    program: {
        // The binary to run for this component.
        binary: "bin/echo_integration_test_cpp",
    },


    // Child components orchestrated by the integration test.
    children: [
        {
            name: "echo_server",
            url: "#meta/echo_server.cm",
        },
    ],

    // Capabilities used by this component.
    use: [
        {
            protocol: [ "fidl.examples.routing.echo.Echo" ],
            from: "#echo_server",
        },
    ],

    // Capabilities required by components under test.
    offer: [
        {
            protocol: [
                "fuchsia.inspect.InspectSink",
                "fuchsia.logger.LogSink",
            ],
            from: "parent",
            to: "#echo_server",
        },
    ],
}

測試控制器程式碼會透過公開的功能與 echo_server 互動:

Rust

use {anyhow::Error, fidl_fidl_examples_routing_echo as fecho, fuchsia_component::client};

#[fuchsia::test]
async fn echo_integration_test() -> Result<(), Error> {
    const ECHO_STRING: &str = "Hello, world!";

    let echo = client::connect_to_protocol::<fecho::EchoMarker>()
        .expect("error connecting to echo server");
    let out = echo.echo_string(Some(ECHO_STRING)).await.expect("echo_string failed");

    assert_eq!(ECHO_STRING, out.unwrap());
    Ok(())
}

C++

#include <fidl/examples/routing/echo/cpp/fidl.h>
#include <lib/fidl/cpp/string.h>
#include <lib/sys/cpp/component_context.h>

#include <string>

#include <gtest/gtest.h>

TEST(EchoIntegrationTest, TestEcho) {
  ::fidl::examples::routing::echo::EchoSyncPtr echo_proxy;
  auto context = sys::ComponentContext::Create();
  context->svc()->Connect(echo_proxy.NewRequest());

  ::fidl::StringPtr request("Hello, world!");
  ::fidl::StringPtr response = nullptr;
  ASSERT_TRUE(echo_proxy->EchoString(request, &response) == ZX_OK);
  ASSERT_TRUE(request == response);
}

測試套件

受測試的所有元件都會納入同一個密封測試套件中。這樣做可讓開發人員在不同環境中執行及更新測試,不必擔心依附元件因依附元件問題而受損。

請參考以下定義本範例的 fuchsia_test_package() 目標的 BUILD.gn 檔案:

Rust

rustc_test("bin") {
  name = "echo_integration_test_rust"
  edition = "2021"

  deps = [
    "//examples/components/routing/fidl:echo_rust",
    "//src/lib/fuchsia",
    "//src/lib/fuchsia-component",
    "//third_party/rust_crates:anyhow",
  ]

  sources = [ "src/lib.rs" ]
}


fuchsia_component("echo_integration_test_component") {
  testonly = true
  component_name = "echo_integration_test"
  manifest = "meta/echo_integration_test.cml"
  deps = [ ":bin" ]
}


fuchsia_test_package("echo_integration_test_rust") {
  test_components = [ ":echo_integration_test_component" ]
  deps = [ "//examples/components/routing/rust/echo_server:echo_server_cmp" ]
}

C++

executable("bin") {
  output_name = "echo_integration_test_cpp"
  sources = [ "echo_integration_test.cc" ]
  deps = [
    "//examples/components/routing/fidl:echo_hlcpp",
    "//sdk/lib/sys/cpp",
    "//sdk/lib/sys/cpp/testing:unit",
    "//src/lib/fxl/test:gtest_main",
    "//third_party/googletest:gtest",
    "//zircon/system/ulib/async-loop:async-loop-cpp",
    "//zircon/system/ulib/async-loop:async-loop-default",
  ]
  testonly = true
}


fuchsia_component("echo_integration_test_component") {
  testonly = true
  component_name = "echo_integration_test"
  manifest = "meta/echo_integration_test.cml"
  deps = [ ":bin" ]
}


fuchsia_test_package("echo_integration_test_cpp") {
  test_components = [ ":echo_integration_test_component" ]
  deps = [ "//examples/components/routing/cpp/echo_server:echo_server_cmp" ]
}

元件使用下列變數內建於 fuchsia_test_package() 中:

  • test_components:包含公開 fuchsia.test.Suite 通訊協定的元件。
  • deps:整合測試所需的其他元件依附元件。

詳情請參閱測試套件 GN 範本

測試元件元件

元件的路徑名稱可識別元件拓撲中不重複的執行個體。針對在測試拓撲內執行的元件,路徑名稱路徑是與測試領域中的根元件相對的相對關係。在上述範例中,根元件是公開 fuchsia.test.Suite 通訊協定的測試控制器元件。

子項的路徑名稱格式取決於您的測試領域拓撲

  • 靜態 CML:以靜態方式宣告根測試控制器子項的元件,只會透過元件 name 識別。
  • Realm Builder:Realm Builder 在測試控制器與子項元件之間引入中繼集合。如要進一步瞭解如何使用 Realm Builder 的測試元件 UI,請參閱「Realm Builder」開發人員指南。