Appium 自动化数据驱动:Excel、Pytest 参数化与断言分流
系列导航
只写一个“登录成功”用例并不难,真正有挑战的是把它扩展成一组可维护的场景:
- 用户名为空;
- 密码为空;
- 用户名不存在;
- 用户名密码不匹配;
- 按钮置灰;
- 登录成功。
如果每个场景都复制一份测试代码,后面会非常难维护。所以这篇聚焦数据驱动:让流程代码尽量不变,把变化放到数据里。
数据驱动的三步
当前材料里的思路很清楚:
- 先准备测试数据;
- 再读取并格式化;
- 最后通过
pytest.mark.parametrize驱动测试执行。
用 Pandas 读取 Excel
示例里给了两种读法。
读成字典列表
PYTHON
def pandas_read_excel_dict(filepath, sheetname):
data = pandas.read_excel(filepath, sheet_name=sheetname)
data = data.where(data.notnull(), '')
datadict = data.to_dict(orient='records')
print(datadict)
return datadict
读成普通列表
PYTHON
def pandas_read_excel_list(filepath, sheetname):
data = pandas.read_excel(filepath, sheet_name=sheetname)
data = data.fillna('')
datalist = data.values.tolist()
print(datalist)
return datalist
为什么这里更推荐字典形式
因为字典形式更适合参数化测试:
- 字段名更直观;
- 后续可以直接用
caseinfo["casename"]、caseinfo["expectedresult"]; - 测试数据和字段语义绑定更紧。
Tip
对入门阶段来说,Excel 很适合做第一版数据源。它足够直观,也方便非开发背景的测试同学维护。
接入 pytest.mark.parametrize
示例里的接法如下:
PYTHON
filepath = 'D:\\Apprun\\examples\\excel_test_data\\kaoyanbang.xlsx'
sheetname = 'Sheet2'
caseinfo = pandas_read_excel_dict(filepath, sheetname)
@pytest.mark.parametrize('caseinfo', caseinfo)
def test_login_success(abcd, caseinfo):
driver = abcd
allure.dynamic.title(caseinfo["casename"])
casedata = eval(caseinfo["allparams"])
这段代码的关键点有三个:
- Excel 每一行对应一条用例;
allure.dynamic.title()可以让报告标题随着数据变化;- 同一套流程代码会被多次执行,但每次参数不同。
参数化之后,断言为什么也要分流
参数化并不意味着所有用例都走同一种断言。
示例里就做了分支处理:
PYTHON
if caseinfo['caseid'] in ['login001', 'login005']:
ele = wait_element(driver, widgetToast)
assert ele.text in eval(caseinfo['expectedresult'])
elif caseinfo['caseid'] in ['login004', 'login002', 'loging003']:
ele = get_element(driver, loginCodeLoginBtn)
assert ele.get_attribute('enabled') == False
这里体现了数据驱动真正有价值的地方:
- 流程可以相同;
- 预期结果不一定相同;
- 不同场景的断言方式也可能完全不同。
这套设计适合哪些断言
在当前材料里,至少已经覆盖了三类:
- 成功场景:断言“跳过”按钮文本;
- 错误提示场景:断言
Toast; - 表单非法场景:断言登录按钮
enabled == False。
这说明数据驱动不是简单地“多跑几组输入”,而是让同一个业务流程可以承载不同的验证目标。
实战里最容易踩的坑
Warning
数据驱动真正难的地方往往不在 parametrize 本身,而在数据格式、断言选择和边界处理。
常见问题包括:
pytest.mark.parametrize拼写错误;- Windows 路径转义处理不对;
find_element和find_elements搞混;Toast没有显式等待就去断言;enabled属性返回值类型没有实际确认;- 测试数据字段命名不稳定,后期很难维护。
当前示例还值得进一步优化的地方
虽然这套代码足以表达思路,但如果往更稳的工程实践走,还有两个点值得改:
eval(caseinfo["allparams"])这在教学示例里方便,但真实项目里更推荐 JSON 或更安全的解析方式。- Excel 字段约定
最好尽早固定清楚,比如:
caseid、casename、allparams、expectedresult各自到底存什么。
小结
数据驱动的核心,不是把 Excel 接进来,而是把“变化”从代码中抽离出来。这样新增场景时,优先改的是数据;只有当流程本身变化时,才需要改测试代码。