桌面 RPA 测试工程化:把脚本变成可度量的测试资产

RPA 脚本最常见的死法不是写不出来,而是写出来之后没人敢动它:没有版本管理、没有测试、没有监控,跑挂了靠人肉发现。RPA 和自动化测试是同一件事的两面,2024 年把 RPA 脚本按测试工程的标准重做了一遍,这篇讲"工程化"到底改了哪些地方。

一、脚本分层:入口 / 流程 / 原子操作

RPA 脚本膨胀的根源是"一个脚本干所有事"。分层之后:

1
2
3
4
5
6
7
8
9
10
11
rpa/
├── entry/ # 入口层:参数解析、启动、退出、上报
│ └── main.py
├── flows/ # 流程层:业务步骤编排(不含控件细节)
│ └── order_reconciliation.py
├── atoms/ # 原子层:单控件/单窗口操作(纯函数式)
│ ├── window.py # 找到窗口/等待/前置
│ ├── grid.py # 表格取值/翻页/筛选
│ └── dialog.py # 弹窗确认/输入
└── knowledge/ # 知识库:窗口特征、控件定位、业务常量
└── windows.yaml

分层规则:

  • 入口层只做三件事:吃参数、调一个 flow、把结果和状态码上报——入口挂了重启无副作用;
  • 流程层编排业务语义(“核对订单”= 打开系统 → 拉取清单 → 逐单核对 → 输出差异),不出现任何控件名
  • 原子层是唯一的控件接触面,每个原子操作幂等、可单独重放;
  • 知识库把"窗口长什么样、控件在哪"从代码里抽出来,UI 微调改 YAML 不改代码。

二、状态机:RPA 脚本必须是可恢复的

UI 自动化脚本崩一次就从头来,RPA 不行——一个跑 3 小时的核对任务,第 2 小时崩了从头跑等于没做。核心是流程级检查点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class FlowRunner:
def __init__(self, flow_id):
self.ckpt = CheckpointStore(f"var/run/{flow_id}")

def run_step(self, step_id, fn):
if self.ckpt.done(step_id):
return self.ckpt.result(step_id) # 已完成:直接取结果
result = fn() # 执行
self.ckpt.mark(step_id, result) # 落盘(原子写:tmp + rename)
return result

# flows/order_reconciliation.py
runner.run_step("fetch_list", fetch_order_list)
for batch in batches:
runner.run_step(f"reconcile:{batch.id}", lambda b=batch: reconcile(b))
runner.run_step("report", build_report)

检查点粒度按"可重放且幂等"切:拉取清单(幂等)是检查点,逐批核对(幂等)每批一个检查点,报告生成(幂等)一个检查点。不可幂等的操作(如"发送通知")必须设计成可重发(带幂等键),否则那个检查点不能落。

崩溃恢复 = 重启入口 → 检查点续跑。实测把 3 小时任务的"崩溃代价"从 3 小时降到平均 11 分钟(一个检查点区间)。

三、失败分类:不是所有失败都要告警

RPA 跑在生产机器上,告警风暴比失败本身更伤。失败四分类,处置各不同:

类别 判定 处置
瞬时 窗口加载慢、网络抖动、目标程序未启动 自动重试(指数退避 3 次),成功则静默记录
环境 目标程序版本变了、控件找不到、分辨率异常 截图 + 控件树 dump,暂停任务,钉钉通知值班
业务 数据校验不通过(订单对不上) 这是 RPA 的产出不是错误,进差异报告
致命 目标系统整体不可用、证书过期 任务终止,升级告警

分类靠错误码约定:原子层抛异常时带类别(RpaError(category, code, context)),入口层按类别走处置表。"业务失败 ≠ 脚本失败"是 RPA 和测试最容易被混淆的点——测试里 assert 失败是期望中的价值,RPA 的"核对出差异"同理,不能当故障报。

四、可度量:RPA 的 SLO

工程化的最后一步是给 RPA 定 SLO,和线上服务一样看板化:

1
2
3
4
5
# RPA SLO(月度)
task_success_rate: 0.995 # 任务级成功率(排除业务差异)
first_pass_rate: 0.97 # 一次通过率(不含重试成功)
recovery_rate: 0.95 # 检查点恢复成功率
mttr_minutes: 15 # 失败到人工介入的时长

看板指标:

  • 任务成功率 = 成功任务 / 计划任务(业务差异不算失败);
  • 一次通过率反映脚本真实健壮性——重试成功率高 = 脚本在吃重试,该修选择器/时序了;
  • 原子操作耗时分布:P95 耗时翻倍往往是"UI 变重了"的早期信号,比等失败更早发现问题。

五、小结

RPA 工程化四件事:分层(入口/流程/原子/知识库,控件只出现在原子层)、检查点(可恢复,崩溃代价从小时级降到分钟级)、失败分类(业务差异不是故障)、SLO 看板(一次通过率、恢复率)。做完这四件,RPA 脚本才配叫"资产"——可以交接、可以演进、可以信任。