

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 設定 IDT 狀態機器
<a name="idt-state-machine"></a>

**重要**  
從 IDT v4.5.2 開始，此狀態機器已棄用。我們強烈建議您使用新的測試協調器。如需詳細資訊，請參閱[設定 IDT 測試協調器](idt-test-orchestrator.md)。

狀態機器是一種控制測試套件執行流程的建構。它決定測試套件的開始狀態、根據使用者定義的規則管理狀態轉換，並繼續轉換這些狀態，直到達到結束狀態為止。

如果您的測試套件不包含使用者定義的狀態機器，IDT 會為您產生狀態機器。預設狀態機器會執行下列函數：
+ 讓測試執行器能夠選取和執行特定測試群組，而不是整個測試套件。
+ 如果未選取特定測試群組， 會以隨機順序執行測試套件中的每個測試群組。
+ 產生報告並列印主控台摘要，顯示每個測試群組和測試案例的測試結果。

IDT 測試套件的狀態機器必須符合下列條件：
+ 每個狀態對應於 IDT 要採取的動作，例如執行測試群組或製作報告檔案的產品。
+ 轉換為 狀態會執行與 狀態相關聯的動作。
+ 每個狀態都會定義下一個狀態的轉換規則。
+ 結束狀態必須為 `Succeed`或 `Fail`。

## 狀態機器格式
<a name="state-machine-format"></a>

您可以使用下列範本來設定自己的`<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 狀態的物件。每個 States.*state-name* 物件都包含映射至 *state-name* 的有效狀態定義。  
`States` 物件必須包含 `Succeed`和 `Fail` 狀態。如需有效狀態的資訊，請參閱 [有效狀態和狀態定義](#valid-states)。

## 有效狀態和狀態定義
<a name="valid-states"></a>

本節說明可在 IDT 狀態機器中使用的所有有效狀態的狀態定義。下列某些狀態支援測試案例層級的組態。不過，建議您在測試群組層級設定狀態轉換規則，而非測試案例層級，除非絕對必要。

**Topics**
+ [RunTask](#state-runtask)
+ [Choice](#state-choice)
+ [平行](#state-parallel)
+ [AddProductFeatures](#state-addproductfeatures)
+ [報告](#state-report)
+ [LogMessage](#state-logmessage)
+ [SelectGroup](#state-selectgroup)
+ [失敗](#state-fail)
+ [Succeed](#state-succeed)

### RunTask
<a name="state-runtask"></a>

`RunTask` 狀態會從測試套件中定義的測試群組執行測試案例。

```
{
    "Type": "RunTask",
    "Next": "<state-name>",
    "TestGroup": "<group-id>",
    "TestCases": [
        "<test-id>"
    ],
    "ResultVar": "<result-name>"
}
```

如下所述，包含值的所有欄位皆為必要：

**`Next`**  
在目前狀態下執行動作後，要轉換為的狀態名稱。

**`TestGroup`**  
選用。要執行的測試群組 ID。如果未指定此值，IDT 會執行測試執行器選取的測試群組。

**`TestCases`**  
選用。來自 中指定群組的測試案例 IDs 陣列`TestGroup`。根據 `TestGroup`和 的值`TestCases`，IDT 會決定測試執行行為，如下所示：  
+ 同時指定 `TestCases` `TestGroup`和 時，IDT 會從測試群組執行指定的測試案例。
+ `TestCases` 指定`TestGroup`但未指定 時，IDT 會執行指定的測試案例。
+ `TestGroup` 指定 但未指定 `TestCases` 時，IDT 會執行指定測試群組中的所有測試案例。
+ 未指定 `TestCases` `TestGroup`或 時，IDT 會從測試執行器從 IDT CLI 中選取的測試群組中執行所有測試案例。若要啟用測試執行器的群組選擇，您必須在 `statemachine.json` 檔案中同時包含 `RunTask`和 `Choice` 狀態。如需如何運作的範例，請參閱[範例狀態機器：執行使用者選取的測試群組](#allow-specific-groups)。

  如需為測試執行器啟用 IDT CLI 命令的詳細資訊，請參閱 [啟用 IDT CLI 命令](test-executables.md#idt-cli-coop)。

**`ResultVar`**  
使用測試執行結果設定的內容變數名稱。如果您未指定 的值，請勿指定此值`TestGroup`。IDT `false`會根據下列項目，將您在 中定義的變數值`ResultVar`設定為 `true`或 ：  
+ 如果變數名稱的格式為 `text_text_passed`，則值會設定為是否通過或略過第一個測試群組中的所有測試。
+ 在所有其他情況下，該值會設定為是否通過或略過所有測試群組中的所有測試。

一般而言，您將使用 `RunTask` 狀態來指定測試群組 ID，而不指定個別測試案例 IDs，以便 IDT 執行指定測試群組中的所有測試案例。此狀態執行的所有測試案例都會以隨機順序平行執行。不過，如果所有測試案例都需要裝置才能執行，而且只有單一裝置可用，則測試案例將改為依序執行。

**錯誤處理**

如果任何指定的測試群組或測試案例 IDs 無效，則此狀態會發出`RunTaskError`執行錯誤。如果狀態遇到執行錯誤，也會將狀態機器內容中的`hasExecutionError`變數設定為 `true`。

### Choice
<a name="state-choice"></a>

`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`。表達式字串會從狀態機器內容擷取值，然後對其執行操作以到達布林值。如需存取狀態機器內容的相關資訊，請參閱 [狀態機器內容](#state-machine-context)。  
**`Choices.Next`**  
如果 中定義的表達式`Choices.Expression`評估為 ，則要轉換為的狀態名稱`true`。

**錯誤處理**

在下列情況下， `Choice` 狀態可能需要錯誤處理：
+ 選擇表達式中的某些變數不存在於狀態機器內容中。
+ 表達式的結果不是布林值。
+ JSON 查詢的結果不是字串、數字或布林值。

您無法使用`Catch`區塊來處理此狀態的錯誤。如果您想要在遇到錯誤時停止執行狀態機器，您必須將 `FallthroughOnError`設定為 `false`。不過，我們建議您將 `FallthroughOnError`設定為 `true`，並根據您的使用案例執行下列其中一項操作：
+ 如果您存取的變數預期在某些情況下不存在，請使用 值`Default`和其他`Choices`區塊來指定下一個狀態。
+ 如果您存取的變數應一律存在，請將`Default`狀態設定為 `Fail`。

### 平行
<a name="state-parallel"></a>

`Parallel` 狀態可讓您彼此平行定義和執行新的狀態機器。

```
{
    "Type": "Parallel",
    "Next": "<state-name>",
    "Branches": [
        <state-machine-definition>
    ]
}
```

如下所述，包含值的所有欄位皆為必要：

**`Next`**  
在目前狀態下執行動作後，要轉換為的狀態名稱。

**`Branches`**  
要執行的狀態機器定義陣列。每個狀態機器定義都必須包含自己的 `StartAt`、 `Succeed`和 `Fail` 狀態。此陣列中的狀態機器定義無法參考其定義以外的狀態。  
由於每個分支狀態機器共用相同的狀態機器內容，因此在一個分支中設定變數，然後從另一個分支讀取這些變數可能會導致意外行為。

`Parallel` 狀態只有在執行所有分支狀態機器之後才會移至下一個狀態。每個需要裝置的狀態都會等待執行，直到裝置可用為止。如果有多個裝置可用，此狀態會從多個群組平行執行測試案例。如果沒有足夠的裝置可用，則測試案例會依序執行。由於測試案例在平行執行時以隨機順序執行，因此可能會使用不同的裝置從相同的測試群組執行測試。

**錯誤處理**

請確定分支狀態機器和父系狀態機器都會轉換為 `Fail` 狀態，以處理執行錯誤。

由於分支狀態機器不會將執行錯誤傳輸至父系狀態機器，因此您無法使用`Catch`區塊來處理分支狀態機器中的執行錯誤。請改為在共用狀態機器內容中使用 `hasExecutionErrors`值。如需如何運作的範例，請參閱 [狀態機器範例：平行執行兩個測試群組](#run-in-parallel)。

### AddProductFeatures
<a name="state-addproductfeatures"></a>

`AddProductFeatures` 狀態可讓您將產品功能新增至 IDT 產生的`awsiotdevicetester_report.xml`檔案。

產品功能是有關裝置可能符合的特定條件的使用者定義資訊。例如，`MQTT`產品功能可以指定裝置正確發佈 MQTT 訊息。在報告中，產品功能會根據是否通過指定的測試，設定為 `supported`、 `not-supported`或自訂值。



**注意**  
`AddProductFeatures` 狀態本身不會產生報告。此狀態必須轉換為 [`Report` 狀態](#state-report)才能產生報告。

```
{
    "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`**  
選用。測試群組 IDs的陣列。每個指定測試群組中的所有測試都必須通過，才能支援此功能。  
**`OneOfGroups`**  
選用。測試群組 IDs的陣列。至少一個指定測試群組內的所有測試都必須通過，才能支援此功能。  
**`TestCases`**  
選用。測試案例 IDs的陣列。如果您指定此值，則適用下列條件：  
+ 所有指定的測試案例都必須通過，才能支援此功能。
+ `Groups` 只能包含一個測試群組 ID。
+ `OneOfGroups` 不得指定。  
**`IsRequired`**  
選用。設定為 `false` 以在報告中將此功能標記為選用功能。預設值為 `true`。  
**`ExecutionMethods`**  
選用。符合 `device.json` 檔案中指定`protocol`值的執行方法陣列。如果指定此值，則測試執行器必須指定`protocol`符合此陣列中其中一個值的值，以在報告中包含 功能。如果未指定此值，則功能一律會包含在報告中。

若要使用 `AddProductFeatures` 狀態，您必須將 `RunTask` 狀態`ResultVar`中的 值設定為下列其中一個值：
+ 如果您指定個別測試案例 IDs，請將 `ResultVar`設定為 `group-id_test-id_passed`。
+ 如果您未指定個別測試案例 IDs，請將 `ResultVar`設定為 `group-id_passed`。

`AddProductFeatures` 狀態會以下列方式檢查測試結果：
+ 如果您未指定任何測試案例 IDs，則每個測試群組的結果取決於狀態機器內容中的 `group-id_passed`變數值。
+ 如果您確實指定測試案例 IDs，則每個測試的結果取決於狀態機器內容中的 `group-id_test-id_passed`變數值。

**錯誤處理**

如果在此狀態下提供的群組 ID 不是有效的群組 ID，則此狀態會導致`AddProductFeaturesError`執行錯誤。如果狀態遇到執行錯誤，則也會將狀態機器內容中的`hasExecutionErrors`變數設定為 `true`。

### 報告
<a name="state-report"></a>

`Report` 狀態會產生 `suite-name_Report.xml`和 `awsiotdevicetester_report.xml` 檔案。此狀態也會將報告串流至 主控台。

```
{
    "Type": "Report",
    "Next": "<state-name>"
}
```

如下所述，包含值的所有欄位皆為必要：

**`Next`**  
在目前狀態下執行動作後，要轉換為的狀態名稱。

您應該一律在測試執行流程結束時轉換為 `Report` 狀態，以便測試執行器可以檢視測試結果。一般而言，此狀態之後的下一個狀態為 `Succeed`。

**錯誤處理**

如果此狀態在產生報告時遇到問題，則會發出`ReportError`執行錯誤。

### LogMessage
<a name="state-logmessage"></a>

`LogMessage` 狀態會產生 `test_manager.log` 檔案，並將日誌訊息串流至 主控台。

```
{
    "Type": "LogMessage",
    "Next": "<state-name>"
    "Level": "info | warn | error"
    "Message": "<message>"
}
```

如下所述，包含值的所有欄位皆為必要：

**`Next`**  
在目前狀態下執行動作後，要轉換為的狀態名稱。

**`Level`**  
建立日誌訊息的錯誤層級。如果您指定的關卡無效，此狀態會產生錯誤訊息並予以捨棄。

**`Message`**  
要記錄的訊息。

### SelectGroup
<a name="state-selectgroup"></a>

`SelectGroup` 狀態會更新狀態機器內容，以指出已選取哪些群組。此狀態設定的值會由任何後續`Choice`狀態使用。

```
{
    "Type": "SelectGroup",
    "Next": "<state-name>"
    "TestGroups": [
        <group-id>"
    ]
}
```

如下所述，包含值的所有欄位皆為必要：

**`Next`**  
在目前狀態下執行動作後，要轉換為的狀態名稱。

**`TestGroups`**  
將標記為選取的測試群組陣列。對於此陣列中的每個測試群組 ID，`group-id_selected`變數會在內容`true`中設定為 。請務必提供有效的測試群組 IDs因為 IDT 不會驗證指定的群組是否存在。

### 失敗
<a name="state-fail"></a>

`Fail` 狀態表示狀態機器未正確執行。這是狀態機器的結束狀態，每個狀態機器定義都必須包含此狀態。

```
{
    "Type": "Fail"
}
```

### Succeed
<a name="state-succeed"></a>

`Succeed` 狀態表示狀態機器已正確執行。這是狀態機器的結束狀態，每個狀態機器定義都必須包含此狀態。

```
{
    "Type": "Succeed"
}
```

## 狀態機器內容
<a name="state-machine-context"></a>

狀態機器內容是唯讀 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`**  
如果測試執行器選取要執行的特定測試群組，而不是整個測試套件，則會建立此金鑰，並包含特定測試群組 IDs的清單。

**`specificTestCases`**  
如果測試執行器選取要執行的特定測試案例，而不是整個測試套件，則會建立此金鑰並包含特定測試案例 IDs的清單。

**`hasExecutionErrors`**  
狀態機器啟動時不會結束。如果任何狀態遇到執行錯誤，則會建立此變數`true`，並在狀態機器執行的剩餘持續時間內設定為 。

您可以使用 JSONPath 表示法查詢內容。狀態定義中 JSONPath 查詢的語法為 `{{$.query}}`。您可以在某些狀態下使用 JSONPath 查詢做為預留位置字串。IDT 會將預留位置字串取代為內容中評估 JSONPath 查詢的值。您可以針對下列值使用預留位置：
+ 狀態`TestCases`的值`RunTask`。
+ `Expression` 值`Choice`狀態。

當您從狀態機器內容存取資料時，請確定符合下列條件：
+ 您的 JSON 路徑必須以 開頭 `$.`
+ 每個值都必須評估為字串、數字或布林值。

如需使用 JSONPath 表示法從內容存取資料的詳細資訊，請參閱 [使用 IDT 內容](idt-context.md)。

## 執行錯誤
<a name="execution-errors"></a>

執行錯誤是狀態機器在執行狀態時遇到的狀態機器定義錯誤。IDT 會記錄`test_manager.log`檔案中每個錯誤的相關資訊，並將日誌訊息串流至主控台。

您可以使用下列方法來處理執行錯誤：
+ 在狀態定義中新增[`Catch`區塊](#catch)。
+ 在狀態機器內容中檢查[`hasExecutionErrors`值](#context)的值。

### 擷取
<a name="catch"></a>

若要使用 `Catch`，請將下列項目新增至您的狀態定義：

```
"Catch": [
    {    
        "ErrorEquals": [
            "<error-type>"
        ]
        "Next": "<state-name>" 
    }
]
```

如下所述，包含值的所有欄位皆為必要：

**`Catch.ErrorEquals`**  
要擷取的錯誤類型陣列。如果執行錯誤符合其中一個指定的值，則狀態機器會轉換為 中指定的狀態`Catch.Next`。如需其產生的錯誤類型的相關資訊，請參閱每個狀態定義。

**`Catch.Next`**  
如果目前狀態遇到符合 中指定其中一個值的執行錯誤，則會轉換為下一個狀態`Catch.ErrorEquals`。

擷取區塊會依序處理，直到一個相符為止。如果沒有錯誤符合 Catch 區塊中列出的錯誤，則狀態機器會繼續執行。由於執行錯誤是不正確狀態定義的結果，我們建議您在狀態遇到執行錯誤時轉換為失敗狀態。

### hasExecutionError
<a name="context"></a>

當某些狀態遇到執行錯誤時，除了發出錯誤之外，也會在狀態機器內容`true`中將`hasExecutionError`值設定為 。您可以使用此值來偵測何時發生錯誤，然後使用 `Choice` 狀態將狀態機器轉換為 `Fail` 狀態。

此方法具有下列特性。
+ 狀態機器不會以指派給 的任何值開頭`hasExecutionError`，且此值在特定狀態設定之前無法使用。這表示您必須針對存取此值`FallthroughOnError``false``Choice`的狀態，將 明確設定為 ，以防止狀態機器在未發生執行錯誤時停止。
+ 一旦設定為 `true`， `hasExecutionError` 永遠不會設定為 false 或從內容中移除。這表示此值只有在第一次設定為 時才有用`true`，而且對於所有後續狀態，它不提供有意義的值。
+ 該`hasExecutionError`值會與 `Parallel` 狀態的所有分支狀態機器共用，這可能會導致非預期的結果，具體取決於存取它的順序。

由於這些特性，如果您可以改用 Catch 區塊，我們不建議您使用此方法。

## 狀態機器範例
<a name="state-machine-examples"></a>

本節提供一些範例狀態機器組態。

**Topics**
+ [狀態機器範例：執行單一測試群組](#single-test-group)
+ [狀態機器範例：執行使用者選取的測試群組](#allow-specific-groups)
+ [狀態機器範例：使用產品功能執行單一測試群組](#run-with-product-features)
+ [狀態機器範例：平行執行兩個測試群組](#run-in-parallel)

### 狀態機器範例：執行單一測試群組
<a name="single-test-group"></a>

此狀態機器：
+ 執行 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"
        }
    }
}
```

### 狀態機器範例：執行使用者選取的測試群組
<a name="allow-specific-groups"></a>

此狀態機器：
+ 檢查測試執行器是否已選取特定測試群組。狀態機器不會檢查特定測試案例，因為測試執行器無法在未同時選取測試群組的情況下選取測試案例。
+ 如果選取測試群組：
  + 在選取的測試群組中執行測試案例。若要這樣做，狀態機器不會明確指定 `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"
        }
    }
}
```

### 狀態機器範例：使用產品功能執行單一測試群組
<a name="run-with-product-features"></a>

此狀態機器：
+ 執行測試群組 `GroupA`。
+ 檢查執行錯誤，並在發現任何 `Fail` 時轉換為 。
+ 將 `FeatureThatDependsOnGroupA`功能新增至 `awsiotdevicetester_report.xml` 檔案：
  + 如果`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"
        }
    }
}
```

### 狀態機器範例：平行執行兩個測試群組
<a name="run-in-parallel"></a>

此狀態機器：
+ 平行執行 `GroupA`和 `GroupB` 測試群組。分支狀態機器中`RunTask`狀態存放在內容中的`ResultVar`變數可供 `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"
        }
    }
}
```