本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
配置 IDT 状态机
重要
从 IDT v4.5.1 开始,此状态机已弃用。强烈建议您使用新的测试管弦乐队。有关更多信息,请参阅 配置 IDT 测试管弦乐队。
状态机是控制测试套件执行流程的构造。它确定测试套件的起始状态,根据用户定义的规则管理状态转换,并继续通过这些状态转换直到达结束状态。
如果您的测试套件不包含用户定义的状态机,IDT 将为您生成状态机。默认状态机执行以下功能:
-
让测试运行者能够选择和运行特定的测试组,而不是整个测试套件。
-
如果未选择特定的测试组,则以随机顺序运行测试套件中的每个测试组。
-
生成报告并打印显示每个测试组和测试用例的测试结果的控制台摘要。
IDT 测试套件的状态机必须满足以下条件:
-
每个州都对应于 IDT 要采取的操作,例如运行测试组或产品报告文件。
-
过渡到状态将执行与状态关联的操作。
-
每个州都定义了下一个状态的过渡规则。
-
终止状态必须为
Succeed
要么Fail
.
状态机格式
您可以使用以下模板配置自己的模板。
file: <custom-test-suite-folder>
/suite/state_machine.json
{ "Comment": "
<description>
", "StartAt": "<state-name>
", "States": { "<state-name>
": { "Type": "<state-type>
", // Additional state configuration } // Required states "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
包含值的所有字段都为必填字段,如下所述:
Comment
-
状态机的描述。
StartAt
-
IDT 开始运行测试套件的状态名称。的价值
StartAt
必须设置为中列出的状态之一。States
对象。 States
-
将用户定义的状态名称映射到有效的 IDT 状态的对象。每个州。
state 名称
对象包含映射到的有效状态的定义state 名称
.这些区域有:
States
对象必须包含Succeed
和Fail
状态。有关有效状态的信息,请参阅。有效的状态和州定义.
有效的状态和州定义
本节介绍可在 IDT 状态机中使用的所有有效状态的状态的状态定义。以下某些状态支持测试用例级别的配置。但是,我们建议您在测试组级别而不是测试用例级别配置状态转换规则,除非绝对必要。
RunTask
这些区域有:RunTask
状态将从测试套件中定义的测试组中运行测试用例。
{ "Type": "RunTask", "Next": "
<state-name>
", "TestGroup": "<group-id>
", "TestCases": [ "<test-id>
" ], "ResultVar": "<result-name>
" }
包含值的所有字段都为必填字段,如下所述:
Next
-
在当前状态下执行操作后,要转换到的状态的名称。
TestGroup
-
可选。要运行的测试组的 ID。如果未指定此值,则 IDT 将运行测试运行者选择的测试组。
TestCases
-
可选。中指定的组中的测试用例 ID 数组
TestGroup
. 基于的价值TestGroup
和TestCases
,IDT 确定测试执行行为如下:-
当这两者时
TestGroup
和TestCases
被指定,IDT 从测试组运行指定的测试用例。 -
何时
TestCases
已指定但TestGroup
未指定,IDT 运行指定的测试用例。 -
何时
TestGroup
已指定,但TestCases
未指定,IDT 将运行指定测试组中的所有测试用例。 -
当两者都不
TestGroup
要么TestCases
,IDT 将运行测试运行者从 IDT CLI 中选择的测试组中的所有测试用例。要为测试跑步者启用小组选择,您必须同时包括两者RunTask
和Choice
在你的状态state_machine.json
文件。有关其工作方式的示例,请参阅。示例状态机:运行用户选择的测试组.有关为测试运行者启用 IDT CLI 命令的更多信息,请参阅。启用 IDT CLI 命令.
-
ResultVar
-
要与测试运行结果一起设置的上下文变量的名称。如果您没有为指定值,请勿指定此值。
TestGroup
. IDT 设置您在中定义的变量的值ResultVar
到true
要么false
根据以下内容:-
如果变量名称为形式
,则该值设置为第一个测试组中的所有测试是通过还是已跳过。text
_text
_passed -
在所有其他情况下,该值设置为所有测试组中的所有测试是通过还是被跳过。
-
通常情况下,您将使用RunTask
状态指定测试组 ID 而不指定单个测试用例 ID,以便 IDT 将运行指定测试组中的所有测试用例。由此状态运行的所有测试用例均以随机顺序 parallel 运行。但是,如果所有测试用例都需要一台设备运行,并且只有一台设备可用,则测试用例将按顺序运行。
错误处理
如果任何指定的测试组或测试用例 ID 无效,则此状态将发出RunTaskError
执行错误。如果状态遇到执行错误,那么它还会设置hasExecutionError
状态机上下文中的变量true
.
Choice
这些区域有:Choice
状态允许您根据用户定义的条件动态设置要转换到的下一个状态。
{ "Type": "Choice", "Default": "
<state-name>
", "FallthroughOnError": true | false, "Choices": [ { "Expression": "<expression>
", "Next": "<state-name>
" } ] }
包含值的所有字段都为必填字段,如下所述:
Default
-
在中没有定义任何表达式时,要转换为的默认状态。
Choices
可以评估true
. FallthroughOnError
-
可选。指定状态在计算表达式时遇到错误时的行为。设置为
true
如果评估导致错误,则想跳过表达式。如果没有匹配表达式,则状态机转换为Default
状态。如果FallthroughOnError
值未指定,默认为false
. Choices
-
用于确定在当前状态下执行操作后转换到哪个状态的表达式和状态数组。
Choices.Expression
-
计算结果为布尔值的表达式字符串。如果表达式的计算结果为
true
,然后状态机转换为中定义的状态。Choices.Next
. 表达式字符串从状态机上下文中检索值,然后对它们执行操作以得出布尔值。有关访问状态机上下文的信息,请参阅状态机上下文. Choices.Next
-
在中定义的表达式时,要转换为的状态的名称。
Choices.Expression
评估为true
.
错误处理
这些区域有:Choice
在以下情况下,状态可能需要错误处理:
-
选择表达式中的某些变量在状态机上下文中不存在。
-
表达式的结果不是布尔值。
-
JSON 查找的结果不是字符串、数字或布尔值。
您不能使用Catch
阻止处理此状态下的错误。如果要在状态机遇到错误时停止执行状态机,则必须设置FallthroughOnError
到false
. 但是,我们建议您设置FallthroughOnError
到true
,并且根据您的使用情形,执行以下操作之一:
-
如果您正在访问的变量在某些情况下预计不存在,则使用
Default
以及其他Choices
块以指定下一个状态。 -
如果你正在访问的变量应该始终存在,那么将
Default
状态Fail
.
Parallel
这些区域有:Parallel
状态允许你彼此并行定义和运 parallel 新的状态机。
{ "Type": "Parallel", "Next": "
<state-name>
", "Branches": [<state-machine-definition>
] }
包含值的所有字段都为必填字段,如下所述:
Next
-
在当前状态下执行操作后,要转换到的状态的名称。
Branches
-
要运行的状态机定义数组。每个状态机定义必须包含自己的定义
StartAt
、Succeed
, 和Fail
状态。此数组中的状态机定义不能引用自己定义之外的状态。注意
由于每台分支状态机共享相同的状态机上下文,因此在一个分支中设置变量然后从另一个分支读取这些变量可能会导致意外行为。
这些区域有:Parallel
状态只有在运行所有分支状态机后才会移动到下一个状态。需要设备的每个状态都将等到设备可用为止。如果有多台设备可用,则此状态并行运 parallel 来自多个组的测试用例。如果没有足够的设备可用,则测试用例将按顺序运行。由于测试用例在并行运行时以随机顺序运 parallel,因此可能会使用不同的设备来运行同一测试组的测试。
错误处理
确保分支状态机和父状态机都过渡到Fail
状态来处理执行错误。
由于分支状态机不会将执行错误传输到父状态机,因此不能使用Catch
阻止来处理分支状态机中的执行错误。请改用hasExecutionErrors
共享状态机上下文中的值。有关其工作方式的示例,请参阅。示例状态机:parallel 行运行两个测试组.
添加产品功能
这些区域有:AddProductFeatures
状态允许您将产品功能添加到awsiotdevicetester_report.xml
IDT 生成的文件。
产品功能是关于设备可能满足的特定标准的用户定义信息。例如,MQTT
产品功能可以指定设备正确发布 MQTT 消息。在报告中,产品功能设置为supported
、not-supported
,或者根据指定的测试是否通过的自定义值。
注意
这些区域有:AddProductFeatures
状态本身不会生成报告。此状态必须过渡到Reportstate以生成报告。
{ "Type": "Parallel", "Next": "
<state-name>
", "Features": [ { "Feature": "<feature-name>
", "Groups": [ "<group-id>
" ], "OneOfGroups": [ "<group-id>
" ], "TestCases": [ "<test-id>
" ], "IsRequired": true | false, "ExecutionMethods": [ "<execution-method>
" ] } ] }
包含值的所有字段都为必填字段,如下所述:
Next
-
在当前状态下执行操作后,要转换到的状态的名称。
Features
-
一系列产品功能将在
awsiotdevicetester_report.xml
文件。Feature
-
功能的名称
FeatureValue
-
可选。要在报表中使用的自定义值,而不是
supported
. 如果未指定此值,则根据测试结果,要素值将设置为supported
要么not-supported
.如果你使用自定义值
FeatureValue
,您可以使用不同的条件测试同一功能,并且 IDT 连接受支持的条件的功能值。例如,以下摘录显示了MyFeature
具有两个单独的功能值的功能:... { "Feature": "MyFeature", "FeatureValue": "first-feature-supported", "Groups": ["first-feature-group"] }, { "Feature": "MyFeature", "FeatureValue": "second-feature-supported", "Groups": ["second-feature-group"] }, ...
如果两个测试组都通过,则要素值将设置为
first-feature-supported, second-feature-supported
. Groups
-
可选。测试组 ID 的数组。每个指定测试组中的所有测试都必须通过,才能支持该功能。
OneOfGroups
-
可选。测试组 ID 的数组。必须通过至少一个指定测试组中的所有测试才能支持该功能。
TestCases
-
可选。测试用例 ID 的数组。如果指定此值,则以下条件适用:
-
必须通过所有指定的测试用例才能支持该功能。
-
Groups
必须只包含一个测试组 ID。 -
OneOfGroups
必须指定不能指定。
-
IsRequired
-
可选。设置为
false
在报告中将此功能标记为可选功能。原设定值为true
。 ExecutionMethods
-
可选。一组与
protocol
中指定的值device.json
文件。如果指定了此值,则测试运行者必须指定protocol
值,该值与此数组中的其中一个值相匹配,以便在报表中包括该功能。如果未指定此值,则该功能将始终包含在报告中。
使用AddProductFeatures
状态,你必须设置的值ResultVar
中的RunTask
状态为以下值之一:
-
如果您指定了单个测试用例 ID,那么请设置
ResultVar
到
.group-id_test-id
_passed -
如果你没有指定单个测试用例 ID,那么设置
ResultVar
到
.group-id
_passed
这些区域有:AddProductFeatures
按以下方式检查测试结果:
-
如果您没有指定任何测试用例 ID,则每个测试组的结果将根据
状态机上下文中的变量。group-id
_passed -
如果您确实指定了测试用例 ID,则每个测试的结果将根据
状态机上下文中的变量。group-id_test-id
_passed
错误处理
如果在此状态下提供的组 ID 不是有效的组 ID,则此状态将导致AddProductFeaturesError
执行错误。如果状态遇到执行错误,那么它还会设置hasExecutionErrors
状态机上下文中的变量true
.
报告
这些区域有:Report
状态机
和suite-name
_Report.xmlawsiotdevicetester_report.xml
文件。此状态还会将报告流式传输到控制台。
{ "Type": "Report", "Next": "
<state-name>
" }
包含值的所有字段都为必填字段,如下所述:
Next
-
在当前状态下执行操作后,要转换到的状态的名称。
你应该始终过渡到Report
状态接近测试执行流程结束,以便测试运行者可以查看测试结果。通常,此状态之后的下一个状态是Succeed
.
错误处理
如果此状态在生成报告时遇到问题,则会发出ReportError
执行错误。
日志消息
这些区域有:LogMessage
状态机test_manager.log
将日志消息传输到控制台。
{ "Type": "LogMessage", "Next": "
<state-name>
" "Level": "info | warn | error" "Message": "<message>
" }
包含值的所有字段都为必填字段,如下所述:
Next
-
在当前状态下执行操作后,要转换到的状态的名称。
Level
-
创建日志消息的错误级别。如果指定的级别无效,则此状态将生成错误消息并将其丢弃。
Message
-
要记录的消息。
选择组
这些区域有:SelectGroup
状态会更新状态机上下文以指示选择了哪些组。此状态设置的值将被任何后续的任何人使用Choice
状态。
{ "Type": "SelectGroup", "Next": "
<state-name>
" "TestGroups": [<group-id>
" ] }
包含值的所有字段都为必填字段,如下所述:
Next
-
在当前状态下执行操作后,要转换到的状态的名称。
TestGroups
-
将标记为选定的测试组的数组。对于此阵列中的每个测试组 ID,
变量设置为group-id
_selectedtrue
在上下文中。确保您提供了有效的测试组 ID,因为 IDT 不会验证指定的组是否存在。
Fail
这些区域有:Fail
状态表示状态机未正确执行。这是状态机的结束状态,每个状态机定义都必须包含此状态。
{ "Type": "Fail" }
Succeed
这些区域有:Succeed
状态表示状态机正确执行。这是状态机的结束状态,每个状态机定义都必须包含此状态。
{ "Type": "Succeed" }
状态机上下文
状态机上下文是一个只读 JSON 文档,其中包含在执行过程中状态机可用的数据。状态机上下文只能从状态机访问,其中包含确定测试流程的信息。例如,您可以使用测试运行者在userdata.json
文件来确定是否需要运行特定测试。
状态机上下文采用以下格式:
{ "pool": {
<device-json-pool-element>
}, "userData": {<userdata-json-content>
}, "config": {<config-json-content>
}, "suiteFailed": true | false, "specificTestGroups": [ "<group-id>" ], "specificTestCases": [ "<test-id>" ], "hasExecutionErrors": true }
pool
-
有关为测试运行选择的设备池的信息。对于选定的设备池,此信息将从中定义的相应顶级设备池阵列元素中检索
device.json
文件。 userData
-
中的信息
userdata.json
文件。 config
-
信息固定
config.json
文件。 suiteFailed
-
该值设置为
false
状态机启动的时间。如果测试组在RunTask
状态,那么该值被设置为true
在状态机执行的剩余时间内。 specificTestGroups
-
如果测试运行者选择要运行的特定测试组而不是整个测试套件,则会创建此密钥并包含特定测试组 ID 的列表。
specificTestCases
-
如果测试运行者选择要运行的特定测试用例而不是整个测试套件,则会创建此密钥并包含特定测试用例 ID 的列表。
hasExecutionErrors
-
状态机启动时不退出。如果任何状态遇到执行错误,则创建此变量并将其设置为
true
在状态机执行的剩余时间内。
您可以使用 jsonPath 表示法查询上下文。状态定义中的 jsonPath 查询的语法为{{$.
. 您可以在某些州内使用 jsonPath 查询作为占位符字符串。IDT 将占位符字符串替换为上下文中已评估的 jsonPath 查询的值。您可以对以下值使用占位符:query
}}
-
这些区域有:
TestCases
中的值RunTask
状态。 -
这些区域有:
Expression
值Choice
状态。
在访问状态机上下文中的数据时,请确保满足以下条件:
-
您的 JSON 路径必须以开头
$.
-
每个值必须计算为字符串、数字或布尔值。
有关使用 JSONPath 表示法访问上下文中的数据的更多信息,请参阅。使用 IDT 上下文.
执行错误
执行错误是状态机定义中的错误,状态机在执行状态时遇到的错误。IDT 将有关每个错误的信息记录在test_manager.log
将日志消息传输到控制台。
您可以使用以下方法处理执行错误:
-
添加Catch街区在州定义中。
-
检查hasExecutionErrors值在状态机上下文中。
抓取
使用Catch
中,将以下内容添加到您的州定义中:
"Catch": [ { "ErrorEquals": [ "
<error-type>
" ] "Next": "<state-name>
" } ]
包含值的所有字段都为必填字段,如下所述:
Catch.ErrorEquals
-
要 catch 的错误类型的数组。如果执行错误与指定的值之一匹配,则状态机转换为中指定的状态。
Catch.Next
. 有关它产生的错误类型的信息,请参阅每个状态定义。 Catch.Next
-
如果当前状态遇到与中指定的值之一匹配的执行错误,则要转换到的下一个状态
Catch.ErrorEquals
.
捕获块按顺序处理,直到一次匹配。如果没有错误与 Catch 块中列出的错误匹配,则状态机将继续执行。由于执行错误是不正确的状态定义造成的,因此我们建议您在遇到执行错误时转换为 “失败” 状态。
有执行错误
当某些州遇到执行错误时,除了发出错误之外,它们还设置hasExecutionError
值true
在状态机上下文中。您可以使用此值来检测何时发生错误,然后使用Choice
状态以将状态机转换为Fail
状态。
该方法具有以下特征。
-
状态机不会以分配给的任何值开始
hasExecutionError
,而且在特定状态设置之前,此值才可用。这意味着您必须明确设置FallthroughOnError
到false
(对于 )Choice
状态,访问此值以防止状态机在没有发生执行错误时停止。 -
一旦它被设置为
true
、hasExecutionError
永远不会设置为 false 或从上下文中删除。这意味着该值只有在第一次设置为时才有用true
,对于后续的所有状态,它并不能提供有意义的价值。 -
这些区域有:
hasExecutionError
值与中的所有分支状态机共享Parallel
状态,这可能会导致意外的结果,具体取决于访问它的顺序。
由于这些特征,如果你可以改用 Catch 块,我们建议你不要使用此方法。
示例状态机
本章节提供了状态机配置示例。
示例状态机:运行单个测试组
状态机:
-
使用 id 运行测试组
GroupA
,必须在套件中存在group.json
文件。 -
检查执行错误并过渡到
Fail
如果找到了。 -
生成报告并过渡到
Succeed
如果没有错误,以及Fail
否则为。
{ "Comment": "Runs a single group and then generates a report.", "StartAt": "RunGroupA", "States": { "RunGroupA": { "Type": "RunTask", "Next": "Report", "TestGroup": "GroupA", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
示例状态机:运行用户选择的测试组
状态机:
-
检查测试运行者是否选择了特定的测试组。状态机不会检查特定的测试用例,因为测试运行者不能在不选择测试组的情况下选择测试用例。
-
如果选择测试组:
-
在选定的测试组内运行测试用例。为此,状态机不会在
RunTask
状态。 -
运行所有测试并退出后生成报告。
-
-
如果未选择测试组:
-
在测试组中运行测试
GroupA
. -
生成报告并退出。
-
{ "Comment": "Runs specific groups if the test runner chose to do that, otherwise runs GroupA.", "StartAt": "SpecificGroupsCheck", "States": { "SpecificGroupsCheck": { "Type": "Choice", "Default": "RunGroupA", "FallthroughOnError": true, "Choices": [ { "Expression": "{{$.specificTestGroups[0]}} != ''", "Next": "RunSpecificGroups" } ] }, "RunSpecificGroups": { "Type": "RunTask", "Next": "Report", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "RunGroupA": { "Type": "RunTask", "Next": "Report", "TestGroup": "GroupA", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
示例状态机:运行具有产品功能的单个测试组
状态机:
-
运行测试组
GroupA
. -
检查执行错误并过渡到
Fail
如果找到了。 -
添加
FeatureThatDependsOnGroupA
功能awsiotdevicetester_report.xml
file:-
如果
GroupA
通行证时,要素设置为supported
. -
该功能在报告中未标记为可选项。
-
-
生成报告并过渡到
Succeed
如果没有错误,以及Fail
否则
{ "Comment": "Runs GroupA and adds product features based on GroupA", "StartAt": "RunGroupA", "States": { "RunGroupA": { "Type": "RunTask", "Next": "AddProductFeatures", "TestGroup": "GroupA", "ResultVar": "GroupA_passed", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "AddProductFeatures": { "Type": "AddProductFeatures", "Next": "Report", "Features": [ { "Feature": "FeatureThatDependsOnGroupA", "Groups": [ "GroupA" ], "IsRequired": true } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
示例状态机:parallel 行运行两个测试组
状态机:
-
运行
GroupA
和GroupB
并行测试 parallel。这些区域有:ResultVar
存储在上下文中的变量RunTask
分支状态机中的状态可供AddProductFeatures
状态。 -
检查执行错误并过渡到
Fail
如果找到了。此状态机不使用Catch
阻止因为该方法无法检测到分支状态机中的执行错误。 -
将功能添加到
awsiotdevicetester_report.xml
基于通过的组的文件-
如果
GroupA
通行证时,要素设置为supported
. -
该功能在报告中未标记为可选项。
-
-
生成报告并过渡到
Succeed
如果没有错误,以及Fail
否则
如果在设备池中配置了两台设备,则两者都配置GroupA
和GroupB
可以同时运行。但是,如果任何一个GroupA
要么GroupB
其中有多个测试,那么两台设备都可以分配给这些测试。如果只配置了一台设备,测试组将按顺序运行。
{ "Comment": "Runs GroupA and GroupB in parallel", "StartAt": "RunGroupAAndB", "States": { "RunGroupAAndB": { "Type": "Parallel", "Next": "CheckForErrors", "Branches": [ { "Comment": "Run GroupA state machine", "StartAt": "RunGroupA", "States": { "RunGroupA": { "Type": "RunTask", "Next": "Succeed", "TestGroup": "GroupA", "ResultVar": "GroupA_passed", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }, { "Comment": "Run GroupB state machine", "StartAt": "RunGroupB", "States": { "RunGroupA": { "Type": "RunTask", "Next": "Succeed", "TestGroup": "GroupB", "ResultVar": "GroupB_passed", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } } ] }, "CheckForErrors": { "Type": "Choice", "Default": "AddProductFeatures", "FallthroughOnError": true, "Choices": [ { "Expression": "{{$.hasExecutionErrors}} == true", "Next": "Fail" } ] }, "AddProductFeatures": { "Type": "AddProductFeatures", "Next": "Report", "Features": [ { "Feature": "FeatureThatDependsOnGroupA", "Groups": [ "GroupA" ], "IsRequired": true }, { "Feature": "FeatureThatDependsOnGroupB", "Groups": [ "GroupB" ], "IsRequired": true } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }