测试 FIDL 协议

前提条件

本教程以 HLCPP 使用入门教程为基础。

概览

本教程介绍了如何为 Echo.EchoString 方法编写测试。本教程将向您介绍如何使用两个实用程序来测试在 HLCPP 中实现的 FIDL 协议:

  • gtest 测试循环夹具 sys::testing::ComponentContextProvider
  • HLCPP 绑定提供的 fidl_test_base.h 文件

如果您要自行编写代码,请删除以下目录:

rm -r examples/fidl/hlcpp/testing/*

该测试将以 examples/fidl/hlcpp/testing/main.cc 编写。

设置依赖项

如需设置依赖项,请执行以下操作:

  1. 添加测试所需的库:

    #include <fuchsia/examples/cpp/fidl.h>
    #include <fuchsia/examples/cpp/fidl_test_base.h>
    #include <lib/fidl/cpp/binding.h>
    #include <lib/sys/cpp/testing/component_context_provider.h>
    
    #include "src/lib/testing/loop_fixture/test_loop_fixture.h"
    
  2. examples/fidl/hlcpp/testing/BUILD.gn 中为测试添加构建规则:

    # Copyright 2020 The Fuchsia Authors. All rights reserved.
    # Use of this source code is governed by a BSD-style license that can be
    # found in the LICENSE file.
    import("//build/components.gni")
    
    executable("bin") {
      testonly = true
      output_name = "example_hlcpp_protocol_test"
      sources = [ "main.cc" ]
      deps = [
        "//examples/fidl/fuchsia.examples:fuchsia.examples_hlcpp",
        "//sdk/lib/fidl/cpp",
        "//sdk/lib/sys/cpp",
        "//sdk/lib/sys/cpp/testing:unit",
        "//src/lib/fxl/test:gtest_main",
        "//src/lib/testing/loop_fixture",
      ]
    }
    
    fuchsia_unittest_package("example-hlcpp-protocol-test") {
      deps = [ ":bin" ]
    }
    
    group("hermetic_tests") {
      testonly = true
      deps = [ ":example-hlcpp-protocol-test" ]
    }
    
    

创建服务器实现

如需创建服务器实现,请执行以下操作:

  1. 为经过测试的 Echo 协议添加实现:

    class EchoImpl : public fuchsia::examples::testing::Echo_TestBase {
     public:
      void EchoString(std::string value, EchoStringCallback callback) override { callback(value); }
      void NotImplemented_(const std::string& name) override {
        std::cout << "Not implemented: " << name << std::endl;
      }
    };
    

    此实现从相应的测试基类继承,而不是从 fuchsia::examples::Echo 继承。这意味着,实现只需替换要测试的方法(在本例中为 EchoString)以及 NotImplemented_ 方法(在调用任何未替换的请求处理程序方法时,就会调用该方法)。

  2. 创建一个测试类,用于封装发布 echo 协议的逻辑:

    class EchoServerInstance {
     public:
      explicit EchoServerInstance(std::unique_ptr<sys::ComponentContext> context) {
        context_ = std::move(context);
        binding_ = std::make_unique<fidl::Binding<fuchsia::examples::Echo>>(&impl_);
        fidl::InterfaceRequestHandler<fuchsia::examples::Echo> handler =
            [&](fidl::InterfaceRequest<fuchsia::examples::Echo> request) {
              binding_->Bind(std::move(request));
            };
        context_->outgoing()->AddPublicService(std::move(handler));
      }
    
     private:
      EchoImpl impl_;
      std::unique_ptr<fidl::Binding<fuchsia::examples::Echo>> binding_;
      std::unique_ptr<sys::ComponentContext> context_;
    };
    

    这类似于服务器教程中介绍的代码,但 fidl::Binding 归类所有。这会在类被销毁时调用绑定的析构函数。这样一来,代码就可以在有新的测试组件上下文实例的情况下,在每个测试用例上发布 echo 协议。

实现测试固件类

class EchoTestFixture : public gtest::TestLoopFixture {
 public:
  void SetUp() override {
    TestLoopFixture::SetUp();
    echo_instance_.reset(new EchoServerInstance(provider_.TakeContext()));
  }

  void TearDown() override {
    TestLoopFixture::TearDown();
    echo_instance_.reset();
  }

 protected:
  fuchsia::examples::EchoPtr GetProxy() {
    fuchsia::examples::EchoPtr echo;
    provider_.ConnectToPublicService(echo.NewRequest());
    return echo;
  }

 private:
  std::unique_ptr<EchoServerInstance> echo_instance_;
  sys::testing::ComponentContextProvider provider_;
};

测试夹具执行以下操作:

  • 保存 ComponentContextProvider 的实例。每个测试都会使用该上下文创建新的测试上下文,并使用 EchoServerInstance 类将 Echo 实现绑定到该上下文。
  • 提供 GetProxy() 方法,用于初始化当前测试组件上下文的代理并返回。

添加测试

以下是您可以使用测试夹具编写的测试示例:

TEST_F(EchoTestFixture, EchoString) {
  fuchsia::examples::EchoPtr proxy = GetProxy();
  bool received_response = false;
  proxy->EchoString("hello there", [&](std::string response) {
    ASSERT_EQ(response, "hello there");
    received_response = true;
  });
  proxy.set_error_handler(
      [](zx_status_t status) { ASSERT_TRUE(false && "should not throw any errors"); });
  RunLoopUntilIdle();
  EXPECT_TRUE(received_response);
}

运行测试

如需运行测试,请执行以下操作:

  1. 配置 GN build 以包含测试:

    fx set core.x64 --with //examples/fidl/hlcpp/testing
    
  2. 运行测试:

    fx test -vo example-hlcpp-protocol-test
    

您应该会看到指示成功的测试输出。

总结

  • gtest::TestLoopFixture 无需样板异步循环设置代码。每个测试用例可以直接调用 RunLoopUntilIdle(),而无需手动管理 async::Loop
  • 借助 ComponentContextProvider,您可以在测试期间轻松模拟组件上下文。例如,这对于为组件提供特定功能很有用。
  • HLCPP 绑定测试基架会为每个协议类提供一个测试库,其中每个方法都有一个占位实现。这样,测试就可以仅实现被测方法。