

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 创建 IDT 测试用例可执行文件
<a name="create-test-executables"></a>

您可以通过以下方式，创建测试用例可执行文件并将其放在测试套件文件夹中：
+ 如果测试套件使用 `test.json` 文件中的参数或环境变量来确定要运行哪些测试，您可以为整个测试套件创建一个测试用例可执行文件，也可为测试套件中的每个测试组分别创建一个测试可执行文件。
+ 对于要基于指定命令运行特定测试的测试套件，您可以为测试套件中的每个测试用例创建一个测试用例可执行文件。

作为测试编写者，您可以决定哪一种方法适合您的用例，并相应地构建测试用例可执行文件。请确保在每个 `test.json` 文件中提供正确的测试用例可执行文件路径，并且指定的可执行文件能够正确地运行。

当所有设备都准备好运行测试用例时，IDT 将会读取以下文件：
+ 所选测试用例的 `test.json` 决定了要启动的进程以及要设置的环境变量。
+ 测试套件的 `suite.json` 决定了要设置的环境变量。

IDT 根据 `test.json` 文件中指定的命令和参数启动所需的测试可执行文件进程，并将必要的环境变量传递给这个进程。

## 使用 IDT 客户端软件开发工具包
<a name="idt-client-sdk"></a>

通过 IDT 客户端软件开发工具包，您可以使用 API 命令来简化在测试可执行文件中编写测试逻辑的方式，这些命令可用于跟 IDT 和被测设备交互。IDT 当前提供以下开发工具包：
+ 适用于 Python 的 IDT 客户端软件开发工具包
+ 适用于 Go 的 IDT 客户端软件开发工具包
+ 适用于 Java 的 IDT 客户端软件开发工具包

这些开发工具包位于 `<device-tester-extract-location>/sdks` 文件夹中。创建新的测试用例可执行文件时，您必须将要使用的软件开发工具包复制到包含测试用例可执行文件的文件夹中，并在代码中引用这个软件开发工具包。本节简要描述了可以在测试用例可执行文件中使用的 API 命令。

**Topics**
+ [设备交互](#api-device-interaction)
+ [IDT 交互](#api-idt-interaction)
+ [主机交互](#api-host-interaction)

### 设备交互
<a name="api-device-interaction"></a>

通过运行以下命令，您无需实施任何其他设备交互和连接管理功能，即可与被测设备通信。

`ExecuteOnDevice`  
允许测试套件在支持 SSH 或 Docker shell 连接的设备上运行 shell 命令。

`CopyToDevice`  
允许测试套件将本地文件从运行 IDT 的主机复制到支持 SSH 或 Docker shell 连接的设备上的指定位置。

`ReadFromDevice`  
允许测试套件从支持 UART 连接的设备的串行端口进行读取。

**注意**  
由于 IDT 不管理使用上下文中设备访问信息与设备建立的直接连接，因此我们建议在测试用例可执行文件中使用这些设备交互 API 命令。但是，如果这些命令不满足测试用例要求，您可以从 IDT 环境中检索设备访问信息，并使用该信息从测试套件建立与设备的直接连接。  
要建立直接连接，请分别在 `device.connectivity` 和 `resource.devices.connectivity` 字段中检索被测设备和资源设备的信息。有关使用 IDT 上下文的更多信息，请参阅 [使用 IDT 上下文](idt-context.md)。

### IDT 交互
<a name="api-idt-interaction"></a>

您可以通过运行以下命令，使测试套件与 IDT 进行通信。

`PollForNotifications`  
允许测试套件检查来自 IDT 的通知。

`GetContextValue `"and"`GetContextString`  
允许测试套件从 IDT 上下文中检索值。有关更多信息，请参阅 [使用 IDT 上下文](idt-context.md)。

`SendResult`  
允许测试套件向 IDT 报告测试用例结果。此命令必须在测试套件中每个测试用例结束时进行调用。

### 主机交互
<a name="api-host-interaction"></a>

您可以通过运行以下命令，使测试套件与主机进行通信。

`PollForNotifications`  
允许测试套件检查来自 IDT 的通知。

`GetContextValue `"and"`GetContextString`  
允许测试套件从 IDT 上下文中检索值。有关更多信息，请参阅 [使用 IDT 上下文](idt-context.md)。

`ExecuteOnHost`  
允许测试套件在本地计算机上运行命令，并使 IDT 能够管理测试用例可执行文件的生命周期。

## 启用 IDT CLI 命令
<a name="idt-cli-coop"></a>

IDT CLI `run-suite` 命令提供了多个选项，允许测试运行器自定义测试执行。要允许测试运行器使用这些选项来运行您的自定义测试套件，您需要实施对 IDT CLI 的支持。如果您不实施支持，测试运行器仍然可以运行测试，但是某些 CLI 选项将无法正常运作。为了提供理想的客户体验，我们建议您在 IDT CLI 中实施对以下 `run-suite` 命令参数的支持：

`timeout-multiplier`  
指定一个大于 1.0 的值，该值将应用于测试运行期间的所有超时。  
测试运行器可以使用此参数来延长他们想要运行的测试用例的超时时间。测试运行器在其 `run-suite` 命令中指定此参数后，IDT 会使用它来计算 IDT\$1TEST\$1TIMEOUT 环境变量的值，并在 IDT 上下文中设置 `config.timeoutMultiplier` 字段。要支持这个参数，您必须执行以下操作：  
+ 读取 IDT\$1TEST\$1TIMEOUT 环境变量来获取正确计算的超时值，而不是直接使用 `test.json` 文件中的超时值。
+ 从 IDT 上下文中检索 `config.timeoutMultiplier` 值，并将其应用于长时间运行的超时。
有关因超时事件而提前退出的更多信息，请参阅[指定退出行为](#test-exec-exiting)。

`stop-on-first-failure`  
指定 IDT 在遇到故障时应当停止运行所有测试。  
测试运行器在其 `run-suite` 命令中指定此参数后，IDT 会在遇到故障时立即停止运行测试。但是，如果测试用例是并行运行的，可能会导致意外的结果。要实施支持，请确保当 IDT 遇到此事件时，您的测试逻辑会指示所有运行中的测试用例停止运行、清理临时资源并向 IDT 报告测试结果。有关失败时提早退出的更多信息，请参阅 [指定退出行为](#test-exec-exiting)。

`group-id`"and"`test-id`  
指定 IDT 应当仅运行选定的测试组或测试用例。  
测试运行器可以在 `run-suite` 命令中使用这些参数来指定以下测试执行行为：  
+ 在指定的测试组中运行所有测试。
+ 运行一组来自指定测试组的测试。
为了支持这些参数，测试套件的测试编排工具必须在测试编排工具中包含一组特定的 `RunTask` 和 `Choice` 状态。如果您不使用自定义状态机，默认 IDT 测试编排工具包含了所需的状态，您无需采取其他操作。但是，如果您要使用自定义测试编排工具，则可以将 [状态机示例：运行用户选择的测试组](idt-state-machine.md#allow-specific-groups) 作为示例，在测试编排工具中添加所需的状态。

有关 IDT CLI 命令的更多信息，请参阅 [调试和运行自定义测试套件](run-debug-custom-tests.md)。

## 写入事件日志
<a name="test-exec-logs"></a>

在测试运行期间，您可以通过向 `stdout` 和 `stderr` 发送数据，将事件日志和错误消息写入控制台。有关控制台消息格式的信息，请参阅 [控制台消息格式](idt-review-results-logs.md#idt-console-format)。

IDT 运行完测试套件后，也可以在 `<devicetester-extract-location>/results/<execution-id>/logs` 文件夹下的 `test_manager.log` 文件中找到此信息。

您可以将每个测试用例配置为将其测试运行的日志（包括来自被测设备的日志）写入 `<device-tester-extract-location>/results/execution-id/logs` 文件夹下的 `<group-id>_<test-id>` 文件中。为此，请使用 `testData.logFilePath` 查询从 IDT 上下文中检索日志文件的路径，在该路径上创建一个文件，然后将所需的内容写入这个文件中。IDT 会根据正在运行的测试用例来自动更新路径。如果您选择不为测试用例创建日志文件，则不会为该测试用例生成任何文件。

此外，也可将文本可执行文件设置为按需在 `<device-tester-extract-location>/logs` 文件夹中创建其他日志文件。我们建议您为日志文件名指定唯一的前缀，以避免您的文件被覆盖。

## 向 IDT 报告结果
<a name="test-exec-results"></a>

IDT 将测试结果写入 `awsiotdevicetester_report.xml` 和 `suite-name_report.xml` 文件中。这些报告文件位于 `<device-tester-extract-location>/results/<execution-id>/` 下。两个报告都捕获测试套件执行的结果。有关 IDT 用于这些报告的架构的更多信息，请参阅 [查看 IDT 测试结果和日志](idt-review-results-logs.md)

要在 `suite-name_report.xml` 文件中填充内容，您必须在测试执行结束前使用 `SendResult` 命令向 IDT 报告测试结果。如果 IDT 找不到测试结果，则会针对该测试用例发出错误。以下 Python 摘录显示了用于向 IDT 发送测试结果的命令：

```
request-variable = SendResultRequest(TestResult(result))
client.send_result(request-variable)
```

如果您不通过 API 报告结果，IDT 会在测试构件文件夹中查找测试结果。此文件夹的路径存储在 IDT 上下文中的 `testData.testArtifactsPath` 文件中。在此文件夹中，IDT 将找到的第一个按字母顺序排序的 XML 文件用作测试结果。

如果您的测试逻辑生成 JUnit XML 结果，您可以将测试结果写入构件文件夹下的 XML 文件中，以直接向 IDT 提供结果，而不必解析结果后再使用 API 将其提交给 IDT。

如果使用此方法，请确保您的测试逻辑准确汇总了测试结果，并将结果文件格式化为与 `suite-name_report.xml` 文件相同的格式。IDT 不会对您提供的数据进行任何验证，但以下情况除外：
+ IDT 会忽略 `testsuites` 标签的所有属性。相反，它会从其他报告的测试组结果计算标签属性。
+ `testsuites` 中必须至少存在一个 `testsuite` 标签。

IDT 对所有测试用例使用相同的构件文件夹，并且不会在两次测试运行之间删除结果文件。因此，如果 IDT 读取了错误的文件，此方法也可能会导致错误的报告。我们建议您在所有测试用例中对生成的 XML 结果文件使用相同的名称，以覆盖每个测试用例的结果，并将正确的结果提供给 IDT 使用。您可以在测试套件中使用混合方法来进行报告，即：对某些测试用例使用 XML 结果文件，同时通过 API 提交其他测试用例的结果。但是，我们不建议采用这种方法。

## 指定退出行为
<a name="test-exec-exiting"></a>

将您的文本可执行文件配置为始终以退出代码 0 退出，即使测试用例报告失败或错误结果时也不例外。仅使用非零退出代码来表示测试用例未运行，或者表示测试用例可执行文件无法向 IDT 传达任何结果。当 IDT 收到非零退出代码时，这表示测试用例遇到了阻碍其运行的错误。

在以下事件中，IDT 可能会请求或期望测试用例在完成之前停止运行。您可以使用此信息来配置测试用例可执行文件，以检测测试用例中的每个事件：

**超时**  
当测试用例的运行时间超过 `test.json` 文件中指定的超时值时发生。如果测试运行器使用 `timeout-multiplier` 参数来指定超时乘数，则 IDT 会使用该乘数来计算超时值。  
要检测此事件，请使用 IDT\$1TEST\$1TIMEOUT 环境变量。当测试运行器启动测试时，IDT 会将 IDT\$1TEST\$1TIMEOUT 环境变量的值设置为计算得出的超时值（以秒为单位），并将该变量传递给测试用例可执行文件。您可以读取变量值来设置相应的计时器。

**中断**  
在测试运行器中断 IDT 时发生。例如，按下 Ctrl\$1C。  
终端会将信号传播到所有子进程，因此您只需在测试用例中配置信号处理程序来检测中断信号即可。  
或者，也可以定期轮询 API 以检查 `PollForNotifications` API 响应中 `CancellationRequested` 布尔值的值。当 IDT 收到中断信号时，它会将 `CancellationRequested` 布尔值设置为 `true`。

**首次失败时停止**  
发生的条件为：与当前测试用例并行运行的测试用例失败，并且测试运行器使用了 `stop-on-first-failure` 参数来指定 IDT 应当在遇到任何失败时停止运行。  
要检测此事件，您可以定期轮询 API 以检查 `PollForNotifications` API 响应中 `CancellationRequested` 布尔值的值。如果 IDT 遇到故障并且已配置为在首次失败时停止，它会将 `CancellationRequested` 布尔值设置为 `true`。

发生其中任何一个事件时，IDT 会等待 5 分钟，让当前正在运行的测试用例完成运行。如果所有正在运行的测试用例未能在 5 分钟内退出，IDT 会强制停止它们的每个进程。如果 IDT 没有在进程结束之前收到测试结果，它会将测试用例标记为已超时。作为一种最佳实践，您应确保测试用例在遇到其中一个事件时执行以下操作：

1. 停止运行正常的测试逻辑。

1. 清理所有的临时资源，例如被测设备上的测试构件。

1. 向 IDT 报告测试结果，例如测试失败或错误。

1. 退出。