| # Integration testing topologies | |
| Integration testing scenarios involve two or more components operating in the | |
| same realm and exchanging capabilities. While the majority of tests are unit | |
| tests that span only a single component, integration testing scenarios call for | |
| defining realm topologies and capability routes. | |
| ## Test Runner Framework integration | |
| The integration test component integrates with the [Test Runner Framework][trf] by | |
| including the test runner shard matching the supported language-specific testing framework. | |
| * {Rust} | |
| ```json5 | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/rust/meta/echo_integration_test.cml" region_tag="shard_include" adjust_indentation="auto" highlight="2" %} | |
| ``` | |
| * {C++} | |
| ```json5 | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/cpp/meta/echo_integration_test.cml" region_tag="shard_include" adjust_indentation="auto" highlight="2" %} | |
| ``` | |
| This shard provides two key elements: | |
| 1. Expose the `fuchsia.test.Suite` protocol, required for the framework to | |
| discover and execute the test cases. | |
| 1. Set the program `runner` to the test runner provided for the given testing | |
| framework. | |
| ## Test realm topology {#test-topology} | |
| The integration test component declares the topology of the test realm with | |
| itself as the parent. This allows the test controller to be responsible for | |
| capability routing between components under test and their dependencies. | |
| The following is an example topology for integration testing the `echo_server` | |
| component: | |
| <br><br> | |
| This is a simple test realm that binds to the `fidl.examples.routing.echo.Echo` | |
| protocol exposed by the `echo_server` component. | |
| The `echo_integration_test` package contains the following components: | |
| - **echo_integration_test** - Test controller component | |
| - **echo_server** - Component under test | |
| You can define the test realm topology in the following ways: | |
| - [Realm Builder](#realm-builder): Dynamically in code using the Realm Builder | |
| library. | |
| - [Component manifests](#static-cml): Statically using component manifest | |
| language (CML). | |
| Use the following table to help determine which approach is best for your integration tests: | |
| <table> | |
| <tr> | |
| <th>Integration test cases</th> | |
| <th>Realm Builder</th> | |
| <th>Static CML</th> | |
| </tr> | |
| <tr> | |
| <td>Simple integration tests with static dependencies</td> | |
| <td><span class="compare-yes"></span></td> | |
| <td><span class="compare-yes"></span></td> | |
| </tr> | |
| <tr> | |
| <td>Unique component instances for each test case</td> | |
| <td><span class="compare-yes"></span></td> | |
| <td><span class="compare-no"></span></td> | |
| </tr> | |
| <tr> | |
| <td>Lifecycle of components under test bound to each test case</td> | |
| <td><span class="compare-yes"></span></td> | |
| <td><span class="compare-no"></span></td> | |
| </tr> | |
| <tr> | |
| <td>Dynamic fake, mock, and stub instances for components under test</td> | |
| <td><span class="compare-yes"></span></td> | |
| <td><span class="compare-no"></span></td> | |
| </tr> | |
| <tr> | |
| <td>Dynamic routing and configuration between test cases</td> | |
| <td><span class="compare-yes"></span></td> | |
| <td><span class="compare-no"></span></td> | |
| </tr> | |
| </table> | |
| ### Realm Builder {#realm-builder} | |
| Note: Consider using a [test realm factory] component rather than using Realm | |
| Builder directly in a test suite. | |
| In cases where realm topology needs to be defined at runtime, or components | |
| need to be replaced with local mock implementations, you can use the Realm Builder | |
| library to create the topology dynamically in your test code. | |
| Note: You can find the example code referenced in this section under | |
| [`//examples/components/realm_builder`][dynamic-example]. | |
| The test controller component's manifest includes the Realm Builder library using | |
| its component manifest shard: | |
| * {Rust} | |
| ```json5 | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/meta/sample_realm.cml" region_tag="include_shard_rust" adjust_indentation="auto" %} | |
| ``` | |
| * {C++} | |
| ```json5 | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/meta/sample_realm.cml" region_tag="include_shard_cpp" adjust_indentation="auto" %} | |
| ``` | |
| The test controller code constructs the test realm topology, adding `echo_server` as a | |
| child component and declaring the necessary capability routes back to the parent: | |
| * {Rust} | |
| ```rust | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/src/lib.rs" region_tag="import_statement_rust" adjust_indentation="auto" %} | |
| // ... | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/src/lib.rs" region_tag="init_realm_builder_rust" adjust_indentation="auto" %} | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/src/lib.rs" region_tag="add_server_rust" adjust_indentation="auto" %} | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/src/lib.rs" region_tag="route_to_test_rust" adjust_indentation="auto" %} | |
| ``` | |
| * {C++} | |
| ```cpp | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/sample.cc" region_tag="import_statement_cpp" adjust_indentation="auto" %} | |
| // ... | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/sample.cc" region_tag="init_realm_builder_cpp" adjust_indentation="auto" %} | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/sample.cc" region_tag="add_server_cpp" adjust_indentation="auto" %} | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/sample.cc" region_tag="route_to_test_cpp" adjust_indentation="auto" %} | |
| ``` | |
| The test controller code interacts with the `echo_server` through the capabilities | |
| exposed by the created realm: | |
| * {Rust} | |
| ```rust | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/src/lib.rs" region_tag="build_realm_rust" adjust_indentation="auto" %} | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/rust/src/lib.rs" region_tag="call_echo_rust" adjust_indentation="auto" %} | |
| ``` | |
| * {C++} | |
| ```cpp | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/sample.cc" region_tag="build_realm_cpp" adjust_indentation="auto" %} | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/realm_builder/cpp/sample.cc" region_tag="call_echo_cpp" adjust_indentation="auto" %} | |
| ``` | |
| For complete details on implementing tests using Realm Builder, see the | |
| [Realm Builder][realm-builder] developer guide. | |
| ### Component manifests {#static-cml} | |
| In cases where all components in the test are static, you can define the entire topology | |
| for the test realm declaratively using CML in the component manifest for the test controller. | |
| Note: You can find the example code referenced in this section under | |
| [`//examples/components/routing/integration_tests`][static-example]. | |
| The test controller component's manifest statically declares the `echo_server` | |
| component under test as a child, and routes the necessary capabilities back to | |
| the parent: | |
| * {Rust} | |
| ```json5 | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/rust/meta/echo_integration_test.cml" region_tag="example_snippet" adjust_indentation="auto" %} | |
| ``` | |
| * {C++} | |
| ```json5 | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/cpp/meta/echo_integration_test.cml" region_tag="example_snippet" adjust_indentation="auto" %} | |
| ``` | |
| The test controller code interacts with the `echo_server` through its exposed | |
| capabilities: | |
| * {Rust} | |
| ```rust | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/rust/src/lib.rs" region_tag="example_snippet" adjust_indentation="auto" %} | |
| ``` | |
| * {C++} | |
| ```cpp | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/cpp/echo_integration_test.cc" region_tag="example_snippet" adjust_indentation="auto" %} | |
| ``` | |
| ## Test package {#test-package} | |
| All components under test are included in the same **hermetic test package**. | |
| This promotes the ability to run and update tests in different environments | |
| without concern for dependencies falling out of sync. | |
| See the following `BUILD.gn` file that defines a `fuchsia_test_package()` target for this example: | |
| * {Rust} | |
| ```gn | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/rust/BUILD.gn" region_tag="example_snippet" adjust_indentation="auto" highlight="22,23,24,25,26" %} | |
| ``` | |
| * {C++} | |
| ```gn | |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/integration_tests/cpp/BUILD.gn" region_tag="example_snippet" adjust_indentation="auto" highlight="23,24,25,26,27" %} | |
| ``` | |
| Components are built into the `fuchsia_test_package()` using the following variables: | |
| - `test_components`: Components containing tests that expose the `fuchsia.test.Suite` protocol. | |
| - `deps`: Additional component dependencies required by the integration test. | |
| For more details, see [Test package GN templates][test-packages]. | |
| ## Test component monikers {#test-component-moniker} | |
| A component's moniker identifies the unique instance in the component topology. | |
| For components running inside of a test topology, the moniker path is relative to | |
| the root component in the test realm. In the above example, the root component is | |
| the test controller component that exposes the `fuchsia.test.Suite` protocol. | |
| The child moniker format depends on your [test realm topology](#test-topology): | |
| - **Static CML**: Components declared statically as children of the root test controller | |
| are simply identified by their component `name`. | |
| - **Realm Builder**: Realm Builder introduces an intermediate collection between | |
| the test controller and child components. For more details on test component | |
| monikers with Realm Builder, see the [Realm Builder][realm-builder-monikers] | |
| developer guide. | |
| [dynamic-example]: /examples/components/realm_builder/ | |
| [static-example]: /examples/components/routing/integration_tests/ | |
| [realm-builder]: /docs/development/testing/components/realm_builder.md | |
| [realm-builder-monikers]: /docs/development/testing/components/realm_builder.md#test-component-moniker | |
| [trf]: test_runner_framework.md | |
| [test-packages]: /docs/development/components/build.md#test-packages | |
| [test realm factory]: /docs/development/testing/components/test_realm_factory.md |