【web 自动化】-6- 数据驱动DDT
一、参数化数据驱动测试
1. 核心概念:“数据驱动测试” 解决什么问题?
场景:测试 “后台登录” 时,用例流程固定(输入账号→密码→登录→断言 ),但需要测不同数据:
- 正确账号密码(正例 )
- 错误密码、空账号(反例 )
传统做法:写多个用例,重复流程代码,只改数据 → 冗余、难维护。
数据驱动测试:用一套流程代码 + 多组测试数据,让用例自动遍历数据执行 → 高效、覆盖全。
2. pytest 实现参数化的核心:@pytest.mark.parametrize
1. 基础用法(数据少直接写死)
import pytest# 测试数据:[(正例), (反例1), (反例2)]
test_data = [("admin", "123456", "登录成功"), # 正例("admin", "wrong_pwd", "密码错误"), # 反例("", "123456", "账号不能为空"), # 反例
]# 参数化装饰器:把 test_data 拆成 username/password/assert_msg 传给用例
@pytest.mark.parametrize("username, password, assert_msg", test_data)
def test_login(username, password, assert_msg):# 模拟登录流程(实际会用 Selenium 操作浏览器)def mock_login(user, pwd):if user == "admin" and pwd == "123456":return "登录成功"elif user == "":return "账号不能为空"else:return "密码错误"# 执行登录result = mock_login(username, password)# 断言结果assert result == assert_msg
效果:
test_login
会自动运行 3 次,每次用不同数据 → 1 套代码覆盖多场景。
3. 结合实际 Web 自动化(Selenium + 参数化)
1. 流程代码(POM 模式,复用之前的设计)
# pages/login_page.py(页面对象,封装登录操作)
from selenium.webdriver.common.by import Byclass LoginPage:def __init__(self, driver):self.driver = driverself.user_input = (By.ID, "username")self.pwd_input = (By.ID, "password")self.login_btn = (By.ID, "login-btn")self.msg = (By.CLASS_NAME, "msg")def input_username(self, user):self.driver.find_element(*self.user_input).send_keys(user)def input_password(self, pwd):self.driver.find_element(*self.pwd_input).send_keys(pwd)def click_login(self):self.driver.find_element(*self.login_btn).click()def get_msg(self):return self.driver.find_element(*self.msg).text
2. 参数化测试用例(数据驱动)
# tests/test_login.py
import pytest
from selenium import webdriver
from pages.login_page import LoginPage# 测试数据(实际可从 CSV/Excel 读取)
test_data = [("admin", "123456", "登录成功"),("admin", "wrong", "密码错误"),("", "123456", "账号不能为空"),
]@pytest.mark.parametrize("username, password, assert_msg", test_data)
def test_login_parametrize(username, password, assert_msg):# 1. 初始化浏览器driver = webdriver.Chrome()driver.get("http://your-login-url.com")driver.maximize_window()# 2. 初始化页面对象login_page = LoginPage(driver)# 3. 执行登录流程login_page.input_username(username)login_page.input_password(password)login_page.click_login()# 4. 获取结果并断言result = login_page.get_msg()assert result == assert_msg# 5. 关闭浏览器driver.quit()
关键点:
@pytest.mark.parametrize
让用例自动遍历test_data
。- 结合 POM 模式,流程代码(输入、点击、断言 )复用,只换数据。
4. 数据量大时:从 CSV/Excel 读取数据
从 CSV 读取
import csvdef get_csv_data():test_data = []with open("login_data.csv", "r", encoding="utf-8") as f:reader = csv.reader(f)next(reader) # 跳过表头for row in reader:test_data.append((row[0], row[1], row[2]))return test_data# 参数化用例,数据来自 CSV
@pytest.mark.parametrize("username, password, assert_msg", get_csv_data())
def test_login_from_csv(username, password, assert_msg):# 同上,执行登录流程...
CSV 文件示例(login_data.csv):
username,password,assert_msg
admin,123456,登录成功
admin,wrong,密码错误
,123456,账号不能为空
5. “数据驱动” 的核心价值
- 高效覆盖场景:1 套流程代码 → 覆盖正例、反例(如密码错误、账号为空 )。
- 数据与代码分离:改数据只需改 CSV/Excel,不用动代码 → 非技术人员也能维护。
- 减少冗余:避免写多个重复用例,代码更简洁。
6. 文中提到的 “注意点” 解析
- 区分正反例:数据里要包含 “正确” 和 “错误” 场景(如正例用正确密码,反例用错误密码 )。
- 页面跳转 / 刷新:执行完登录后,需确保页面跳转正确(如断言 URL 变化 )。
- 页面处理结果:登录后可能有弹窗、提示信息,需用代码捕获并断言(如
get_msg
方法 )。
二、Csv
一、CSV 文件基础认知
- 特点:文本格式存数据,表格形式展示(逗号分隔字段,换行分隔行 )。
- 作用:把测试数据(如登录的用户名、密码、预期结果 )从代码中分离,便于维护和扩展。
二、get_csv_data()
:读取 CSV 数据
def get_csv_data():list1 = []# 打开 CSV 文件,指定编码为 UTF-8cl = csv.reader(open(r"D:\Project234_web\data\后台登录数据内容.csv", encoding="UTF-8"))for i in cl:list1.append(i) # 逐行读取,存入列表return list1
- 功能:读取 CSV 文件内容,返回一个二维列表。
- 示例:若 CSV 内容是
admin,123,登录成功 test,456,密码错误
返回[["admin","123","登录成功"], ["test","456","密码错误"]]
。
- 示例:若 CSV 内容是
- 细节:
csv.reader
:按行解析 CSV,每行数据是一个列表。- 硬编码路径
r"D:\Project234_web\data\..."
:实际项目建议用动态路径(如os.path
拼接 )。
三、pytest.mark.parametrize
:参数化驱动测试
@pytest.mark.parametrize("username,password,assert_msg", get_csv_data())
def test_admin_parameterize(driver, username, password, assert_msg):# 1. 打开登录页driver.get("http://47.107.116.139/fangwei/m.php?m=Public&a=login&")driver.maximize_window()# 2. 初始化页面对象(POM 模式)page = BackgroundLoginPage(driver)# 3. 处理验证码(假设 save_code_img 是截图/识别验证码的逻辑)code = save_code_img(driver)# 4. 执行登录,获取返回信息msg = page.login(username, password, code)print(msg)assert msg == assert_msg
- 核心逻辑:
- 参数化标记:
@pytest.mark.parametrize
会遍历get_csv_data()
返回的列表,把每行数据拆分为username
、password
、assert_msg
,传给测试用例。 - 数据驱动测试:相当于自动生成多组测试用例,每组用不同的 CSV 数据执行登录流程。
- 参数化标记:
四、完整流程与价值
- 数据分离:测试数据存在 CSV,改数据不用动代码。
- 多组用例:一行 CSV 数据对应一条测试用例,自动执行多组登录场景(如正确 / 错误密码 )。
- 复用性:
get_csv_data()
可被其他用例调用,parametrize
让参数化逻辑通用。
三、Excel
一、核心目标
把测试数据(如登录账号、密码、预期结果 )存在 Excel 里,用代码读取后,驱动自动化测试(如登录流程 ),实现 “数据与代码分离”,让测试更灵活(改数据只需改 Excel,不用动代码 )。
二、依赖库:xlrd
- 作用:Python 中用于读取 Excel(
.xls
、.xlsx
)文件的库。 - 安装:
pip install xlrd
(注意:xlrd
对新版.xlsx
支持有限,若报错可换openpyxl
等库 )。
三、代码逐行解析
# 使用Excel表格读取数据
import xlrd# 1. 打开Excel文件
xls = xlrd.open_workbook("D:\Project234_web\data\msjy3.xlsx")# 2. 获取指定Sheet(通过下标,0 表示第一个Sheet)
sheet = xls.sheet_by_index(0)# (可选)查看Sheet的列数、行数
# print(sheet.ncols) # 输出列数
# print(sheet.nrows) # 输出行数(包含表头)# 3. 遍历读取数据(跳过表头,从第1行开始)
list1 = []
for i in range(1, sheet.nrows): # range(1, 行数):跳过第0行(表头)# 获取第i行的所有单元格值,返回列表row_data = sheet.row_values(i) list1.append(row_data) # 存入结果列表else:# 遍历结束后执行(可选:打印读取的结果)print(list1)
四、关键逻辑说明
-
打开 Excel 文件:
xlrd.open_workbook("路径")
:传入 Excel 文件的绝对路径,加载整个工作簿。 -
选择 Sheet:
sheet_by_index(0)
:通过下标选 Sheet(0
是第一个 Sheet )。- 也可用
sheet_by_name("Sheet1")
:按 Sheet 名称选择(更直观 )。
-
读取数据:
sheet.nrows
:获取 Sheet 的总行数(包含表头 )。range(1, sheet.nrows)
:从第 2 行开始遍历(下标从 0 开始,1
对应 Excel 的第 2 行 ),跳过表头。sheet.row_values(i)
:获取第i
行的所有单元格值,返回一个列表(如["admin", "123", "登录成功"]
)。
-
数据存储:
把每行数据存入list1
,最终list1
是二维列表,可用于pytest.mark.parametrize
实现参数化测试。
五、与自动化测试结合(延伸)
读取 Excel 数据后,可结合 pytest
参数化,让测试用例自动遍历 Excel 数据执行:
import pytest# (上面的Excel读取代码,封装成 get_excel_data 函数)
def get_excel_data():import xlrdxls = xlrd.open_workbook("D:\Project234_web\data\msjy3.xlsx")sheet = xls.sheet_by_index(0)list1 = []for i in range(1, sheet.nrows):list1.append(sheet.row_values(i))return list1# 参数化测试用例,遍历 Excel 数据
@pytest.mark.parametrize("username, password, assert_msg", get_excel_data())
def test_login(username, password, assert_msg):# 这里写自动化测试逻辑(如:打开登录页、输入账号密码、断言结果)print(f"测试:{username} / {password},预期:{assert_msg}")# 实际执行:driver.get(...) / driver.find_element(...) 等
六、优缺点与替代方案
优点:
- 数据直观:Excel 表格比 CSV 更易编辑、维护(支持合并单元格、样式 )。
- 适合非技术人员:运营 / 产品可直接改 Excel 数据,无需动代码。
缺点:
- 库的局限性:
xlrd
对新版.xlsx
兼容性差(如 Excel 2007+ 格式 ),复杂表格可能解析异常。 - 性能一般:大文件(万行级 )读取较慢。
替代方案:
- 用
openpyxl
库(支持.xlsx
,功能更全 )。 - 用
pandas
库(pd.read_excel
更简洁,适合数据分析场景 )。
简单说,这是 “Excel 数据驱动测试” 的基础实现:用 xlrd
读 Excel 数据,存成列表后,可结合 pytest
让测试用例自动遍历数据执行,提升测试效率和数据可维护性 。
四、自动化生成缺陷报告
需要使用第三方库:
- allure
- 测试报告生成的框架
- 安装 allure 项目包
- allure-2.8.1
- 配置环境变量
- 一定要先安装 java 的 sdk(环境)
- jdk-17_windows-x64_bin.exe
- 参考 java 环境安装.docx
- java 环境配置
- allure 环境配置
- python 环境中安装 allure-pytest
- pip install allure-pytest
- 在 pytest.ini 配置文件中,添加缺陷报告的输出路径
- addopts = -vs --alluredir report
- 用例执行完成之后,才能生成测试报告
- 输入命令: allure generate report/-o report/html
- 可以查看项目下面的 report 文件夹里面的 html 文件中的 index.html
五、POM 与 KDT 设计模式对比
一、POM 设计模式(Page Object Model)
核心结构:
- Page 类:封装页面元素定位和操作方法
- Test 类:调用 Page 类方法实现测试逻辑
# pages/login_page.py (登录页面对象)
from selenium.webdriver.common.by import Byclass LoginPage:# 元素定位器USERNAME_INPUT = (By.ID, "username")PASSWORD_INPUT = (By.ID, "password")LOGIN_BUTTON = (By.ID, "login-button")def __init__(self, driver):self.driver = driverdef input_username(self, username):self.driver.find_element(*self.USERNAME_INPUT).send_keys(username)def input_password(self, password):self.driver.find_element(*self.PASSWORD_INPUT).send_keys(password)def click_login(self):self.driver.find_element(*self.LOGIN_BUTTON).click()def login(self, username, password):self.input_username(username)self.input_password(password)self.click_login()# tests/test_login.py (测试用例)
def test_successful_login(driver):login_page = LoginPage(driver)login_page.login("admin", "password123")# 断言登录成功后的元素存在assert "Welcome" in driver.page_source
二、KDT 设计模式(Keyword Driven Testing)
核心结构:
- 关键字库:封装基础操作(如点击、输入)
- 测试数据:用表格(Excel/CSV)存储测试步骤
- 执行引擎:解析表格数据,调用关键字执行测试
# keywords/webdriver_keywords.py (关键字库)
from selenium.webdriver.common.by import Byclass WebDriverKeywords:def __init__(self, driver):self.driver = driverdef open_url(self, url):self.driver.get(url)def input_text(self, locator_type, locator_value, text):element = self.driver.find_element(getattr(By, locator_type.upper()), locator_value)element.send_keys(text)def click_element(self, locator_type, locator_value):element = self.driver.find_element(getattr(By, locator_type.upper()), locator_value)element.click()def assert_text(self, expected_text):assert expected_text in self.driver.page_source# engine/keyword_engine.py (执行引擎)
import pandas as pdclass KeywordEngine:def __init__(self, driver):self.driver = driverself.keywords = WebDriverKeywords(driver)def execute_test(self, test_file):# 读取Excel测试用例df = pd.read_excel(test_file)# 逐行执行测试步骤for index, row in df.iterrows():keyword = getattr(self.keywords, row["Keyword"])args = row[1:].dropna().tolist()keyword(*args)# tests/test_login_kdt.py (测试用例)
def test_successful_login_kdt(driver):engine = KeywordEngine(driver)engine.execute_test("tests/data/login_test.xlsx")
测试数据 Excel 示例(login_test.xlsx):
Keyword | Parameter1 | Parameter2 | Parameter3 |
---|---|---|---|
open_url | http://example.com | ||
input_text | id | username | admin |
input_text | id | password | password123 |
click_element | id | login-button | |
assert_text | Welcome |
三、对比分析
维度 | POM | KDT |
---|---|---|
代码结构 | 按页面组织,每个 Page 类对应一个页面 | 按功能组织,关键字库和执行引擎分离,测试数据外部化(Excel/CSV) |
变化应对 | 页面元素变化需修改对应 Page 类 | 修改 Excel 中的测试步骤或参数,无需改代码 |
用例编写 | 测试人员编写 Python 代码 | 非技术人员可通过 Excel 编写测试步骤 |
复用性 | 页面方法可复用,但跨页面复用需组合调用 | 关键字可自由组合,复用性更高 |
复杂度 | 适合中小型项目,页面数量可控 | 适合大型、流程复杂项目,尤其需频繁变更测试步骤的场景 |
四、实际应用建议
-
选 POM 的场景:
- 页面结构稳定,元素定位变化少
- 测试团队技术能力强,偏好维护代码而非表格
- 需要精细控制页面交互细节
-
选 KDT 的场景:
- 业务流程复杂且频繁变更
- 需要产品 / 运营人员参与编写测试用例
- 希望通过配置文件而非代码快速调整测试逻辑
-
混合模式:
- 复杂项目可结合两种模式:核心页面用 POM 封装,业务流程用 KDT 编排
- 例如:
# KDT 中调用 POM def execute_pom_action(self, page_name, action, *args):page_class = getattr(pages, page_name)page = page_class(self.driver)action_method = getattr(page, action)action_method(*args)
五、关键差异总结
场景 | POM 实现 | KDT 实现 |
---|---|---|
页面元素 ID 变更 | 修改对应 Page 类中的定位器 | 无需修改代码,调整 Excel 中的定位参数 |
新增测试用例 | 编写新的测试函数,调用 Page 方法 | 在 Excel 中新增测试步骤行 |
跨项目复用 | 复制 Page 类到新项目 | 导出关键字库和 Excel 模板到新项目 |
非技术人员参与测试 | 需要培训 Python | 只需熟悉 Excel 表格填写 |
通过以上对比可以看出,KDT 更适合需求快速变化、需多方协作的场景,而 POM 更适合结构稳定、技术主导的项目。根据你的项目特性选择,能显著提升自动化测试的效率和可维护性。