测试智能体实战: 云服务 Redis 5.0 升级 7.0 全流程

智能体测试系统架构把"AI 参与测试"拆成了七个阶段,这篇用一句话把它们归拢成测试工程师熟悉的三个词,再用一个完整案例——公司云服务把 Redis 从 5.0 升级到 7.0——走一遍每个阶段智能体怎么用、产出什么。

三个词与七阶段的对应关系

阶段

包含的七阶段环节

核心问题

主要产出

测试策略

1 需求理解

测什么、不测什么、风险在哪、怎么算通过

需求点清单 + 测试策略契约(JSON)

测试设计

2 用例生成、3 用例评审、4 脚本生成

怎么测、用什么数据、怎么断言

编号化用例、分级评审意见、可执行脚本

测试执行

5 用例执行(传统框架,非 AI)、6 失败分诊、7 报告生成

实际结果是什么、失败是谁的问题、能不能发布

执行结果、分诊结论、测试报告

三条贯穿全程的纪律(出处见架构篇,案例里每一步都会体现):

  1. 阶段间只传结构化契约,不传对话历史——下游永远面对确定的 JSON;

  2. 生成与评审分离,用不同模型/不同会话,防止"自己认可自己";

  3. 强制证据:预期结果必须引用文档原文出处,文档没写的标"需澄清",不许编造。

案例背景

公司云数据库服务(多租户、按实例计费、主从+哨兵架构)计划把引擎从 Redis 5.0 升级到 7.0。输入给测试智能体的材料:

docs/requirements/redis-7-upgrade.md   # 升级需求: 在线热升级、数据不丢、租户无感
docs/api/redis-cloud-openapi.yaml      # 云服务控制台 API(创建/升降级实例等)
docs/redis/5-to-7-changelog.md         # 官方 release notes 整理(兼容性变更清单)
tests/cases/                           # 历史用例库(5.0 时代的存量用例)
docs/errcode/redis-cloud.md            # 云服务错误码表

升级的技术风险点(这部分是领域知识,人来准备,写进需求文档):

  • 兼容性: 废弃命令(SLAVEOF → REPLICAOF、BRPOPLPUSH → BLMOVE)、行为变更(部分命令返回错误码变化)、RESP3 协议默认不启用但客户端可能协商;

  • 数据: RDB/AOF 版本兼容(7.0 能读 5.0 的 RDB,反之不行——回滚路径是高危点);

  • 新特性是否开放: Function(FCALL)、Sharded Pub/Sub、ACL v2 selector——多租户云服务通常要禁用或隔离,这本身就是测试点;

  • 云服务特有: 在线升级过程的连接闪断、升级中实例的配额/计费一致性、控制台"升级中"状态机、多租户隔离不因升级破防。

第一阶段: 测试策略(对应阶段 1 需求理解)

智能体干什么: 读齐所有输入材料,把"升级 Redis"这件模糊的事拆成结构化需求点清单,并给出策略判断——范围、优先级、不测什么、通过标准。

Prompt(模板库中的 strategy 模板填槽后)

你是资深云服务测试专家。阅读以下材料:
- docs/requirements/redis-7-upgrade.md
- docs/redis/5-to-7-changelog.md
- docs/api/redis-cloud-openapi.yaml
- docs/errcode/redis-cloud.md

为 Redis 5.0 → 7.0 升级输出测试策略, 保存为 tests/strategy/redis-7.json, 要求:
1. 需求点清单: 每条含 id / 描述 / 出处(文件+章节) / 风险等级(P0-P2) / 建议测试类型
2. 策略判断: 测试范围、明确不测的项(给理由)、环境拓扑、发布通过标准(量化)
3. 兼容性变更逐条列出: 废弃命令、行为变更、协议变更, 每条标注对存量租户的影响面
4. 文档没明确说明的行为, 标 "需澄清" 并列出向谁澄清, 不许编造
5. 只输出符合 schema 的 JSON

输出: 测试策略契约(节选)

{
  "requirement_points": [
    {"id": "RP-01", "desc": "实例在线热升级, 数据零丢失, 业务连接闪断 < 5s",
     "source": "docs/requirements/redis-7-upgrade.md#2.1", "risk": "P0",
     "test_types": ["功能", "可靠性", "性能"]},
    {"id": "RP-02", "desc": "废弃命令 SLAVEOF/BRPOPLPUSH 的兼容策略: 代理层映射或拒绝",
     "source": "docs/redis/5-to-7-changelog.md#deprecated", "risk": "P0",
     "test_types": ["兼容性"], "note": "需澄清: 需求文档未说明代理层是否做命令映射, 找架构组确认"},
    {"id": "RP-03", "desc": "新命令 FCALL/FUNCTION 在多租户下禁用, 调用返回明确错误码",
     "source": "docs/requirements/redis-7-upgrade.md#4.3", "risk": "P1",
     "test_types": ["功能", "安全"]},
    {"id": "RP-04", "desc": "升级失败可回滚到 5.0, 回滚后数据与升级前一致",
     "source": "docs/requirements/redis-7-upgrade.md#2.4", "risk": "P0",
     "test_types": ["可靠性"], "note": "高危: 7.0 写的 RDB 5.0 读不了, 回滚依赖升级前快照"}
  ],
  "scope": {
    "in": ["兼容命令集", "在线升级流程", "回滚", "控制台 API 状态机", "配额计费一致性", "多租户隔离", "性能回归基准"],
    "out": [
      {"item": "Redis Cluster 模式", "reason": "本期产品只卖主从+哨兵形态"},
      {"item": "RESP3 协议", "reason": "服务端默认不启用, 客户端兼容由客户端团队负责"}
    ]
  },
  "environment": "3 套: 5.0 存量实例池 / 升级中实例 / 7.0 新实例池, 每套 3 租户",
  "pass_criteria": "P0 用例 100% 通过; P1 ≥ 95%; 性能回归(基准 ops/sec)退化 < 3%; 升级过程数据一致性校验零差异"
}

人的动作: 评审策略契约——重点看 out(不测的项)和 需澄清 条目,这些是 AI 最容易"默默漏掉"的地方。澄清结论(如"代理层做 SLAVEOF→REPLICAOF 映射")回填需求文档后,策略阶段重跑——DAG 节点缓存机制下,只有这一个节点重算。

第二阶段: 测试设计(阶段 2-4)

步骤 2.1 用例生成(阶段 2)

你是资深云服务测试专家。阅读 tests/strategy/redis-7.json 中 RP-01~RP-04 及引用文档,
为每条需求点设计用例, 保存到 tests/cases/redis-7-upgrade.md, 要求:
1. 每个需求点按矩阵展开: 正常流 / 边界 / 权限(跨租户越权) / 升级中状态 / 回滚路径
2. 兼容性专项: 5-to-7-changelog.md 中每条废弃/变更命令各一条用例, 断言 5.0 与 7.0 行为差异
3. 每条用例: 编号 / 关联需求点 / 前置条件 / 步骤 / 预期结果 / 优先级
4. 预期结果必须引用文档原文出处; 文档没写的标 "需澄清", 不许编造

输出: 用例文件(节选)

编号

需求点

用例

预期结果

优先级

TC-0101

RP-01

实例写入 10 万 key 后触发在线升级, 升级前后逐 key 校验

数据零差异; 闪断期间客户端自动重连成功(出处: 需求文档 2.1)

P0

TC-0201

RP-02

5.0 和 7.0 实例分别执行 SLAVEOF host port

7.0 返回 "unknown command" 或被代理映射为 REPLICAOF(需澄清, 依赖 RP-02 澄清结论)

P0

TC-0207

RP-02

7.0 实例执行 BRPOPLPUSH k1 k2 0

与 changelog 记录的废弃行为一致(出处: changelog#deprecated)

P1

TC-0301

RP-03

租户 A 执行 FCALL mylib 1 k

返回云服务错误码 Redis.CommandDisabled(出处: 错误码表 #redis)

P1

TC-0302

RP-03

租户 A 通过 ACL 尝试给自己加 FCALL 权限后调用

仍被拒; 且不影响租户 B(越权隔离)

P1

TC-0401

RP-04

升级中注入失败(杀掉 7.0 节点), 触发回滚

回滚到 5.0, 数据 = 升级前快照(出处: 需求文档 2.4)

P0

TC-0501

RP-01

升级中查询实例配额与计费计量

计量不中断、不重复计费(需求文档未说明计量精度, 需澄清)

P1

步骤 2.2 用例评审(阶段 3, 换模型评审)

claude -p "你是测试评审员, 只审 tests/cases/redis-7-upgrade.md, 不修改任何文件。
对照 tests/strategy/redis-7.json、docs/redis/5-to-7-changelog.md 和错误码表逐项检查:
1. 遗漏: 哪些需求点/废弃命令/错误码没有对应用例
2. 错误: 哪些预期结果与文档矛盾或无出处
每条意见给出 文档出处 + 用例编号, 按 阻断/建议 分级, 不写客套话" \
  --dangerously-skip-permissions --allowedTools "Read,Grep,Glob" \
  > tests/cases/redis-7-upgrade.review.md

输出: 评审意见(节选)

[阻断] TC-0201 的预期结果仍是"需澄清", 但 RP-02 的澄清结论已回填需求文档 3.2 节
       (代理层映射), 用例未同步更新。出处: docs/requirements/redis-7-upgrade.md#3.2
[阻断] changelog#protocol 列出 "SUBSCRIBE 在事务上下文中行为变更", 无用例覆盖。
[建议] TC-0101 只校验 key 内容, 建议补充 TTL 与 expire 存活校验(7.0 对过期
       删除时机有内部调整, 出处: changelog#expiry)。
[建议] 缺性能回归用例: 策略 pass_criteria 要求 ops/sec 退化 < 3%, 无用例对应。

评审意见喂回生成方修订一到两轮,定稿(人工确认)后进入脚本生成。

步骤 2.3 脚本生成(阶段 4)

根据 tests/cases/redis-7-upgrade.md 中 P0/P1 用例, 生成 pytest 测试脚本,
保存到 tests/api/test_redis7_upgrade.py, 要求:
- 框架 pytest + redis-py, 连接信息从环境变量读取
- 每个测试标注对应用例编号, 方便回溯
- 禁止修改用例文件和策略 JSON

输出: 可执行脚本(节选)

import os, redis, pytest

def conn(ver):  # REDIS_50_URL / REDIS_70_URL
    return redis.Redis.from_url(os.environ[f"REDIS_{ver}_URL"])

def test_tc_0201_slaveof_removed():
    """TC-0201: 7.0 上 SLAVEOF 行为(直连引擎, 绕过代理层验证兜底)"""
    r7 = conn("70")
    with pytest.raises(redis.ResponseError):
        r7.execute_command("SLAVEOF", "127.0.0.1", 6379)

def test_tc_0301_fcall_disabled_for_tenant():
    """TC-0301: 多租户下 FCALL 返回云服务错误码"""
    r = conn("70")
    with pytest.raises(redis.ResponseError, match="Redis.CommandDisabled"):
        r.execute_command("FCALL", "mylib", 1, "k")

@pytest.mark.p0
def test_tc_0401_rollback_data_consistency(upgrade_fixture):
    """TC-0401: 注入升级失败, 回滚后数据等于升级前快照"""
    before = snapshot_keys(conn("50"))
    upgrade_fixture.inject_failure(node="redis7-new")
    upgrade_fixture.wait_rollback()
    assert snapshot_keys(conn("50")) == before

第三阶段: 测试执行(阶段 5-7)

步骤 3.1 执行(阶段 5, 非 AI)

执行用传统测试框架和执行机,智能体不参与判断对错——这是架构篇的明确边界: 执行是确定性工作,AI 的价值在上下游的设计与归因。执行机跑完产出原始结果:

collected 47 items
tests/api/test_redis7_upgrade.py::test_tc_0201_slaveof_removed PASSED
tests/api/test_redis7_upgrade.py::test_tc_0301_fcall_disabled_for_tenant FAILED
tests/api/test_redis7_upgrade.py::test_tc_0401_rollback_data_consistency FAILED
===== 2 failed, 45 passed in 312.4s =====

步骤 3.2 失败分诊(阶段 6)

kimi -p "你是云服务测试失败分诊专家。下面是 Redis 7 升级测试的失败日志和最近 20 条提交。
只输出一个 JSON 对象, 不要 markdown 代码块:
{\"root_cause\": \"一句话根因\", \"evidence\": \"关键日志原文\",
 \"suspect_commits\": [\"hash\"], \"is_flaky\": true/false,
 \"confidence\": 0到1, \"suggested_owner\": \"嫌疑模块\", \"next_action\": \"建议下一步\"}

日志:
$(tail -n 800 ci-failure.log)

最近提交:
$(git log --oneline -20)"

输出: 分诊结论

[
  {"case": "TC-0301",
   "root_cause": "FCALL 未被禁用而是返回了 Redis 原生 NOAUTH 错误, 疑似代理层命令黑名单配置未下发到 7.0 实例组",
   "evidence": "redis.ResponseError: NOAUTH Authentication required (期望 Redis.CommandDisabled)",
   "suspect_commits": ["a1b2c3d (proxy: command filter 支持按引擎版本分组)"],
   "is_flaky": false, "confidence": 0.85,
   "suggested_owner": "proxy-gateway",
   "next_action": "检查 proxy 命令过滤配置对 engine_version=7.0 分组是否生效"},
  {"case": "TC-0401",
   "root_cause": "回滚后丢失升级窗口内写入的 3 个 key, 快照机制只覆盖升级前数据",
   "evidence": "AssertionError: missing keys {'w:1001','w:1002','w:1003'} — 均为 upgrade_window 期间写入",
   "suspect_commits": [], "is_flaky": false, "confidence": 0.95,
   "suggested_owner": "upgrade-orchestrator",
   "next_action": "这是产品设计问题而非实现 bug: 回滚语义需明确'升级窗口写入是否保留', 升级需求文档"}
]

注意第二条: suggested_owner 指向了需求文档——分诊把"实现 bug"和"需求没定义清楚"区分开,这正是强制证据纪律的回报。confidence 低的条目人工深挖,这两条高置信度直接转缺陷单/澄清单。

步骤 3.3 报告生成(阶段 7)

根据本次执行结果与分诊结论(附 JSON), 生成 Redis 7 升级测试报告,
保存到 reports/redis-7-upgrade-2026-W42.md, 要求:
1. 按策略契约的 pass_criteria 逐条判定: 达成/未达成/无法判定(给原因)
2. 每个未达成项附: 用例编号 + 分诊结论 + 缺陷单链接占位
3. 给出发布建议: 通过 / 有条件通过(列条件) / 不通过

输出: 报告结论(节选)

发布建议: 不通过(P0 阻断 2 项)

| 通过标准 | 结果 | 证据 |
|---------|------|------|
| P0 用例 100% 通过 | 未达成 | TC-0301(缺陷: proxy 黑名单未对 7.0 生效)、TC-0401(回滚丢升级窗口数据) |
| 性能退化 < 3% | 达成 | 基准 142k ops/sec vs 5.0 的 138k, 无退化 |
| 升级数据一致性零差异 | 未达成 | TC-0401 见上 |

需产品决策: 回滚语义是否承诺保留升级窗口写入(RP-04 的语义边界), 决策后更新
需求文档并重跑 RP-04 相关节点。

收尾: 沉淀回流(飞轮转一圈)

案例跑完不是结束,按"沉淀触发器"纪律,复盘时只问一句"这次有什么值得固化":

本次经验

沉淀到哪

"Redis 类引擎升级测试, 回滚语义必须显式定义升级窗口写入"

知识层: docs/playbook/engine-upgrade.md 新增一节

"代理层配置按引擎版本分组下发" 这个失败模式

模板层: 分诊 prompt 加一行判断提示; 长期进 golden 集

人工定稿的用例与分诊结论

抽 10% 回流 golden 评测集, 下次换模型时回归用

TC-0201 这类"依赖澄清结论"的用例写法

模板层: 用例生成模板增加"引用需求点澄清状态"字段

总结

  • 测试策略回答"测什么": 智能体读齐材料产策略契约,人审 out 和 需澄清;

  • 测试设计回答"怎么测": 生成-评审对抗出用例,再落成脚本,全程编号可回溯;

  • 测试执行回答"结果怎样": 执行交给传统框架,AI 只做失败分诊与报告——判断对错的权力(oracle)不外包给 AI,这是三个阶段共同的底线。

参考资料