---
title: "测试流水线（管道）编写指南及最佳实践"
language: "zh"
url: "https://docs.testany.io/zh/docs/test-pipeline-writing-guideline-and-samples/"
markdown_url: "https://docs.testany.io/zh/docs/test-pipeline-writing-guideline-and-samples.md"
translation: "https://docs.testany.io/en/docs/test-pipeline-writing-guideline-and-samples.md"
last_updated: "2026-03-26T15:39:24+08:00"
---

# 测试流水线（管道）编写指南及最佳实践

测试流水线是Testany平台中最重要的元素之一。高效地使用和维护测试流水线可以显著提升自动化测试的效率，并提高故障排除的准确性和效率。

[视频](https://customer-en3hmhs3okg5hi37.cloudflarestream.com/f110c3c600f901d29949c6f1afd7563e/watch)

## 准备工作

流水线用于编排测试用例。每个在Testany中注册的测试用例都会有一个唯一的用例键值，你可以使用这些键值来构建流水线。

你可以从测试用例库中获取相关的测试用例键值。

![](https://docs.testany.io/docs/images/zh/image-20230903-100101_2ed27fac.png)

在这个例子中，你有6个不同的测试用例，我们将使用其中的4个，它们的键值分别是：`AC2F5A50`，`9686C618`，`43D41CA4` 和 `8FF75E7F`。

## 了解流水线YAML

在 Testany 平台中，流水线用于表达测试用例之间的逻辑关系及其在执行过程中的其他关联因素。对于今天的新建 Pipeline，你可以把它理解为一张由规则和依赖关系组成的执行图：有依赖的规则按条件推进，没有显式依赖的同层规则则可以被平台并行调度。为了方便编写和维护流水线，我们选择 YAML 作为定义流水线的数据序列化格式。

## 编写流水线YAML文件

在 Testany 平台中，我们使用具有预定义语法格式的 YAML 文件来定义流水线，也称为流水线编排。对于所有新建 Pipeline，建议使用 `rule/v1.3`；`rule/v1.2` 继续兼容历史 Pipeline，但不具备 case 级并行执行能力。


> **说明**
>
> 对于新建 Pipeline，推荐口径很明确：
>
> - 新建 Pipeline 使用 `rule/v1.3`
> - 历史 `rule/v1.2` Pipeline 继续可运行
> - `rule/v1.3` 的默认并发度取决于实例类型：社区版默认 `2`，社区版付费用户默认 `4`，企业版默认 `8`


对于流水线编排，你需要遵循以下语法（推荐基于 `rule/v1.3`）：

- `run`: 定义要执行的测试用例。
- `whenPassed`: 定义一个条件，表示当测试用例 `<TEST-CASE-KEY>` 执行并成功时，调用 `run` 中定义的测试用例。
- `whenFailed`: 定义一个条件，表示当测试用例 `<TEST-CASE-KEY>` 执行失败时，调用 `run` 中定义的测试用例。
- `expect: fail`: 这个属性用于更改测试用例的执行状态。对于流水线执行状态的定义，如果所有执行的测试用例状态都是`Passed`，那么流水线的执行状态就是`Passed`，否则流水线的执行状态为`Failed`。如果某个测试用例的执行状态为`Failed`，并且这个失败是**预期**的，你可以使用这个属性将其状态更改为`Passed`，以使流水线的执行状态为`Success`。
- `relay`: 具有该属性的测试用例可以在执行完成后，将其预先声明的变量值作为输入传递给同一流水线中的其他测试用例。`rule/v1.2` 与 `rule/v1.3` 都支持 relay，但对所有新建 Pipeline 推荐使用 `rule/v1.3`。

例如：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: <TEST-CASE-KEY>
    - whenPassed: <TEST-CASE-KEY>
      run: <TEST-CASE-KEY>
    - whenFailed: <TEST-CASE-KEY>
      run: <TEST-CASE-KEY>
    - whenFailed: <TEST-CASE-KEY>
      run: <TEST-CASE-KEY>
```

将上述的执行逻辑写成符合Testany 测试流水线语法的yaml文件，如下所示：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: AC2F5A50
    - whenPassed: AC2F5A50
      run: 9686C618
    - whenFailed: 9686C618
      run: 43D41CA4
    - whenFailed: 9686C618
      run: 8FF75E7F
```

这个yaml文件所代表的意思是：

```text
invoke AC2F5A50
if AC2F5A50 executed with Passed then
    invoke 9686C618
    if 9686C618 executed with Failed then
        invoke 43D41CA4
        invoke 8FF75E7F
    else
        pipeline completed
else
  pipeline completed
```

将该执行逻辑画成流程图的话，就如下图所示：

![](https://docs.testany.io/docs/images/zh/image-20230903-105302_bbe33d71.png)

### **流水线执行结果规则**

当流水线被编排并执行时，会生成流水线执行状态。关于状态的详细定义及其出现的条件，请参考[《Testany平台状态解读：全面指南》](https://docs.testany.io/zh/docs/understanding-statuses-on-testany-platform-your-co.md) 。

对于上面的例子，如果 AC2F5A50 执行成功，而 9686C618 执行失败，那么流水线的执行结果将是“Failure”。

在实际的测试工作中，有一种比较特殊的情况，就是我们非常清楚某个测试用例的结果将是失败，而且这个结果是预期的（例如，在代码准备之前测试脚本已经准备好）。对于这种情况，Testany特别提供了一个语法：expect: fail。例如：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: AC2F5A50
    - whenPassed: AC2F5A50
      run: 9686C618
      expect: fail
    - whenFailed: 9686C618
      run: 43D41CA4
    - whenFailed: 9686C618
      run: 8FF75E7F
```

在这个例子中，你知道 `9686C618` 将执行失败，并且该失败是预期的，因此即使 `9686C618` 失败了，你仍然希望流水线的执行状态为成功。你可以在 `run:9686C618`(第7行）后添加 `expect: fail`

### 触发条件选择指南

使用以下决策树来选择适合您流水线的触发条件：

![触发条件决策树](https://docs.testany.io/docs/images/zh/trigger-condition-decision-tree.svg)

**常见场景：**

| 业务场景 | 配置方式 | 示例 |
|---------|---------|------|
| 顺序 API 调用 | `whenPassed` | 登录 → 创建订单 → 查询订单 |
| 测试后清理（总是执行） | 不设条件 | 测试 → 清理数据 |
| 负向测试（预期失败） | 该用例设置 `expect: fail`，后续用例用 `whenPassed` | 测试无效输入 → 下一个测试 |
| 失败时的条件分支 | `whenFailed` | 主流程失败 → 执行备用方案 |

**要点说明：**

- `whenPassed`：当被引用的用例**向 Pipeline 报告 Passed** 时执行
- `whenFailed`：当被引用的用例**向 Pipeline 报告 Failed**、**Aborted** 或 **Timeout** 时执行
- `expect: fail`：该用例**始终向 Pipeline 报告 Passed**，无论实际结果如何。后续用例应使用 `whenPassed`（而非 `whenFailed`）来跟随它。
- 不设条件：在 `rule/v1.3` 中表示这些 rule 之间没有显式依赖，平台可按当前工作区可用并发度并行调度；在 `rule/v1.2` 中仍按 legacy 串行语义理解

### `rule/v1.3` 下的并行调度说明

- `rule/v1.3` 表达的是依赖关系，不是“必须同时起跑”的承诺。
- 当多个 case 在语义上同时 ready 时，平台会按当前工作区可用并发度启动它们。
- 如果 ready 的 case 数多于当前工作区可用并发度，未启动的 case 会进入等待队列，并在槽位释放后按 YAML 顺序补位启动。
- 如果某个下游 case 依赖 relay 输出，请确保提供 relay 的测试脚本能在消费 relay 的测试脚本启动前稳定完成；不要把 relay 建在可能同时启动的 sibling 关系上。

### 流水线编排示例：

让我们用几个例子来进一步说明如何编排一个满足测试要求和业务逻辑的流水线，使您的自动化测试更加准确和高效。

#### 示例 A（有效）：whenFailed条件下执行单一用例

场景：“当前一个用例失败时，执行下一个用例。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: AC2F5A50
    - whenFailed: AC2F5A50
      run: 9686C618
    - whenFailed: 9686C618
      run: 43D41CA4
    - whenFailed: 43D41CA4
      run: 8FF75E7F
```

流程图

![](https://docs.testany.io/docs/images/zh/image-20230903-110918_37115bff.png)

#### 示例 B（有效）：whenPassed条件下执行单一用例

场景：“当前一个用例的执行结果为”Pass”时，执行下一个用例。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: AC2F5A50
    - whenPassed: AC2F5A50
      run: 9686C618
    - whenPassed: 9686C618
      run: 43D41CA4
    - whenPassed: 43D41CA4
      run: 8FF75E7F
```

流程图

![](https://docs.testany.io/docs/images/zh/image-20230903-111327_5fcc8af1.png)

#### 示例 C（有效）：whenFailed条件下执行多条用例

场景：“当前一个用例失败时，执行接下来的三个用例。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: AC2F5A50
    - whenFailed: AC2F5A50
      run: 9686C618
    - whenFailed: AC2F5A50
      run: 43D41CA4
    - whenFailed: AC2F5A50
      run: 8FF75E7F
```

流程图

![](https://docs.testany.io/docs/images/zh/image-20230903-111514_0d90cd88.png)

#### 示例 D（有效）：无条件执行

场景：“这四个用例之间没有显式依赖。在 `rule/v1.3` 下，它们在语义上可以并行执行；当可用并发槽位不足时，平台按 YAML 顺序补位启动。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
    - run: AC2F5A50
    - run: 9686C618
    - run: 43D41CA4
    - run: 8FF75E7F
```

流程图：

![](https://docs.testany.io/docs/images/zh/image-20230903-111757_b887d96a.png)

#### 示例 E（有效）：带中继且whenPassed的执行

场景：“这是一个标准且有效的输出中继示例。用例 `DE96D6A0` 从用例 `5DC1106D` 获取 `ACCESS_TOKEN`，用例 `3FD642B7` 也从 `5DC1106D` 获取 `ACCESS_TOKEN`。输出从 `5DC1106D` 中继到 `DE96D6A0`，以及从 `5DC1106D` 中继到 `3FD642B7`。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
  - run: F8C8B1EA
  - whenPassed: F8C8B1EA
    run: 5DC1106D
  - whenPassed: 5DC1106D
    run: DE96D6A0
    relay:
    - key: ACCESS_TOKEN                 # Define an environment variable 'ACCESS_TOKEN' for case 'DE96D6A0'
      refKey: 5DC1106D/ACCESS_TOKEN     # Set case 'DE96D6A0's 'ACCESS_TOKEN' equal to case '5DC1106D's 'ACCESS_TOKEN'
  - whenPassed: 5DC1106D
    run: 3FD642B7
    relay:
    - key: ACCESS_TOKEN                 # Define an environment variable 'ACCESS_TOKEN' for case '3FD642B7'
      refKey: 5DC1106D/ACCESS_TOKEN     # Set case '3FD642B7's 'ACCESS_TOKEN' equal to case '5DC1106D's 'ACCESS_TOKEN'
    - key: STATUS                       # Define an environment variable 'STATUS' for case '3FD642B7'
      refKey: F8C8B1EA/STATUS           # Set case '3FD642B7's 'STATUS' equal to case 'F8C8B1EA's 'STATUS'
      nonSecret: true                   # Set case '3FD642B7's 'STATUS' as non-secret (its value can be printed out in log)
```

流程图：

![image-20250305-090312.png](https://docs.testany.io/docs/images/zh/image-20250305-090312_47cea55b.png)

#### 示例 F（无效）：带中继且whenFailed的执行

场景：“用户在 YAML 中定义用例 B 同时中继了用例 A 并包含 `whenFailed: A`，系统将认为该 YAML **无效**。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
  - run: 5385B189
  - run: A3D9405F
    whenFailed: 5385B189
    relay:
    - key: NEW_URL
      refKey: 5385B189/NEW_URL
      nonSecret: true
    - key: AAA
      refKey: 5385B189/AAA
      nonSecret: true
```

![image-20240923-091726.png](https://docs.testany.io/docs/images/zh/da8f8580-b802-42bd-bf87-a5ac6fc805ac_media-blob-ur_4047b241.png)

#### 示例 G（有效）：带中继的执行

场景：“用户在 YAML 中明确定义 B 中继 A，但未明确声明 B 的其他 `whenpassed` 或 `whenfailed`，此时系统会隐式添加 `whenpassed: A`。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
  - run: 5385B189
  - run: A3D9405F
    relay:
    - key: NEW_URL               # 定义环境变量测试用例'5385B189'的环境变量'NEW_URL'
      refKey: 5385B189/NEW_URL   # 定义测试用例'A3D9405F'的环境变量'NEW_URL'为来自测试用例'5385B189'的环境变量'NEW_URL'
      nonSecret: true
    - key: AAA                   # 定义环境变量测试用例'5385B189'的环境变量'AAA'
      refKey: 5385B189/AAA       # 定义测试用例'A3D9405F'的环境变量'AAA'为来自测试用例'5385B189'的环境变量'AAA'
      nonSecret: true
```

![image-20240924-095302.png](https://docs.testany.io/docs/images/zh/image-20240924-095302_661d380b.png)

#### 示例 H（无效）：中继输出用例未正确配置

场景：“用例 B 依赖于用例 A 的输出，但用例 A 未声明任何输出。在这种情况下，系统不会拒绝配置，但在流水线详细信息页面中，用户将看不到任何标记为中继输出用例标志的测试用例。同时，系统会提醒用户检查依赖关系设置。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
  - run: 4035A27B
  - run: D2ADC651
    relay:
    - key: ACCESS_TOKEN
      refKey: 4035A27B/ACCESS_TOKEN
```

![image-20240924-101013.png](https://docs.testany.io/docs/images/zh/image-20240924-101013_2e9ee4ed.png)

用例 A 配置了中继的情况。

![image-20240924-101131.png](https://docs.testany.io/docs/images/zh/image-20240924-101131_506f5e7e.png)

用例 A 未配置中继的情况。

![image-20240924-101105.png](https://docs.testany.io/docs/images/zh/image-20240924-101105_537bd977.png)

#### 示例 I（无效）：用例之间相互依赖

场景：“用例之间相互依赖形成循环，在这种情况下，系统将认为 YAML **无效**。”

流水线 Yaml：

```yaml
kind: rule/v1.3
spec:
  rules:
  - whenPassed: 9D9671B4
    run: 714A0A51
  - whenPassed: 714A0A51
    run: D2ADC651
  - whenPassed: D2ADC651
    run: 9D9671B4
```

![image-20240924-102837.png](https://docs.testany.io/docs/images/zh/image-20240924-102837_8ed2be39.png)

## 本页术语

- [测试流水线 (Test Pipeline)](https://docs.testany.io/zh/docs/glossary.md#test-pipeline)
- [测试用例 (Test Case)](https://docs.testany.io/zh/docs/glossary.md#test-case)
- [测试用例库（Test Case Library）](https://docs.testany.io/zh/docs/glossary.md#test-case-library)
- [执行 (Execution)](https://docs.testany.io/zh/docs/glossary.md#execution)
- [用户 (User)](https://docs.testany.io/zh/docs/glossary.md#user)
- [测试脚本 (Test Script)](https://docs.testany.io/zh/docs/glossary.md#test-script)
- [工作区 (Workspace)](https://docs.testany.io/zh/docs/glossary.md#workspace)
- [输出中继 (Output Relay)](https://docs.testany.io/zh/docs/glossary.md#output-relay)
