robotframework,一个有趣的 Python 库!
Robot Framework 这个库,有点像给测试脚本装了个翻译器
接口回归又挂了。
日志里就一行:
order_status expect=PAID actual=INIT trace_id=pay_20240629_8f31
这种问题我一般不急着翻业务代码,先看测试脚本。很多项目的自动化测试写到后面,会变成一堆 requests.post()、assert、sleep,再夹几个环境变量。刚开始还行,半年后谁碰谁烦。
Robot Framework 有意思的地方就在这。
它不是让你少写测试,而是把“测试步骤”从 Python 代码里拆出来。业务同学能看懂步骤,测试同学能改用例,底下真正干活的关键字,还是我们用 Python 写。
Robot Framework 是一个开源自动化框架,常用于测试自动化和 RPA,官方也把它描述成基于关键字驱动、可扩展的自动化框架。它本身可以通过 Python 扩展自定义库,安装也就是常规的 pip install robotframework。现在 PyPI 上的说明里也写了,它需要 Python 3.8 或更新版本。
先装:
pip install robotframework
我不太喜欢一上来就写登录百度、打开浏览器那种 demo。太虚。拿一个更像现场的接口回归来说:创建订单、模拟支付回调、查订单状态。
目录大概这样:
case_demo/
libs/
order_keywords.py
tests/
order_flow.robot
Python 关键字库我一般会写得短一点,别搞成框架套框架:
# libs/order_keywords.py
import time
import requestsclassOrderKeywords:
def__init__(self):
self.host = "http://127.0.0.1:8080"
self.last_order_id = None
defcreate_order_for_user(self, user_id: str, amount: int):
payload = {
"userId": user_id,
"amount": amount,
"source": "robot_regression"
}
r = requests.post(
f"{self.host}/api/orders",
json=payload,
timeout=3
)
if r.status_code != 200:
raise AssertionError(f"create order failed, code={r.status_code}, body={r.text}")
body = r.json()
self.last_order_id = body.get("orderId")
ifnot self.last_order_id:
raise AssertionError(f"orderId missing, response={body}")
return self.last_order_id
defmock_pay_callback(self):
ifnot self.last_order_id:
raise AssertionError("last_order_id is empty, create order first")
r = requests.post(
f"{self.host}/api/pay/callback",
json={"orderId": self.last_order_id, "payChannel": "mock"},
timeout=3
)
if r.status_code != 200:
raise AssertionError(f"pay callback failed, body={r.text}")
deforder_status_should_be(self, expect_status: str):
deadline = time.time() + 5
while time.time() < deadline:
r = requests.get(
f"{self.host}/api/orders/{self.last_order_id}",
timeout=2
)
body = r.json()
actual = body.get("status")
if actual == expect_status:
return
time.sleep(0.5)
raise AssertionError(
f"order_status expect={expect_status} actual={actual} order_id={self.last_order_id}"
)
这个类里的方法名,Robot Framework 会自动当成关键字用。比如 create_order_for_user,在 .robot 文件里就可以写成 Create Order For User。
测试用例长这样:
*** Settings ***
Library ../libs/order_keywords.py*** Test Cases ***
订单支付后状态应该变成已支付
${order_id}= Create Order For User user_10086 59
Mock Pay Callback
Order Status Should Be PAID
跑一下:
robot -d reports tests/order_flow.robot
跑完以后,它会生成报告。
这里我觉得 Robot Framework 比较舒服的一点,不是语法多高级,而是报告够直接。哪个步骤挂了,参数是什么,错误信息是什么,基本能顺着看下去。
比如上面的状态没变,它抛出来的不是冷冰冰的 False is not true,而是这句:
order_status expect=PAID actual=INIT order_id=O202406290012
这个错误信息是自己写的。别小看这点。
线上排障很多时间不是花在修 bug 上,是花在“这玩意儿到底挂在哪一步”上。自动化测试也一样。脚本写得再多,失败日志看不懂,最后还是靠人肉点页面。
Robot Framework 还有一个地方挺适合团队协作:用例文件不用塞太多技术细节。
像这个:
订单支付后状态应该变成已支付
Create Order For User user_10086 59
Mock Pay Callback
Order Status Should Be PAID
产品、测试、后端都能看懂。真正怎么发请求、怎么等状态、怎么处理超时,藏在 Python 里。
不过这库也不是万能的。
我见过有人把 Robot Framework 写成另一种“屎山”:一个关键字里面再调十几个关键字,变量满天飞,最后比 Python 还难读。
我的习惯是,Robot 文件只写业务步骤,Python 文件只写稳定动作。不要在 Robot 里写太复杂的判断,也不要把 Python 关键字拆得像积木碎片。
比如这种我就不太信:
Run Keyword If '${status}' == 'INIT' Sleep 3s
Run Keyword If '${status}' == 'INIT' Query Again
Run Keyword If '${status}' != 'PAID' Fail
这种逻辑放 Robot 里,刚开始看着灵活,后面就是灾难。等待、重试、异常兜底,老老实实放 Python 里。
Robot Framework 适合什么?
适合接口回归、冒烟测试、业务流程验收、跨系统联调检查。尤其是那种“步骤很业务,但动作很固定”的场景。
不太适合什么?
不太适合拿来写很细的单元测试,也不适合强行替代 pytest。单元测试该用 pytest 还是用 pytest。Robot Framework 更像是站在业务流程上往下压一层。
我的判断很简单:如果你的测试脚本已经开始出现大量重复请求、重复登录、重复断言,而且失败报告没人愿意看,可以试试 Robot Framework。
它不神,但挺实用。
尤其是配上 Python 自定义关键字以后,它就不是一个“测试人员专用工具”,而是一个能把接口回归、业务验收、排障脚本揉在一起的自动化壳子。
别把它写复杂,就挺好用。