【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 By

class LoginPage:
    def __init__(self, driver):
        self.driver = driver
        self.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 csv

def 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. 高效覆盖场景:1 套流程代码 → 覆盖正例、反例(如密码错误、账号为空 )。
  2. 数据与代码分离:改数据只需改 CSV/Excel,不用动代码 → 非技术人员也能维护。
  3. 减少冗余:避免写多个重复用例,代码更简洁。

 

6. 文中提到的 “注意点” 解析

  1. 区分正反例:数据里要包含 “正确” 和 “错误” 场景(如正例用正确密码,反例用错误密码 )。
  2. 页面跳转 / 刷新:执行完登录后,需确保页面跳转正确(如断言 URL 变化 )。
  3. 页面处理结果:登录后可能有弹窗、提示信息,需用代码捕获并断言(如 get_msg 方法 )。

 

二、Csv

一、CSV 文件基础认知

  • 特点:文本格式存数据,表格形式展示(逗号分隔字段,换行分隔行 )。
  • 作用:把测试数据(如登录的用户名、密码、预期结果 )从代码中分离,便于维护和扩展。

二、get_csv_data():读取 CSV 数据

def get_csv_data():
    list1 = []
    # 打开 CSV 文件,指定编码为 UTF-8
    cl = 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.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 

  • 核心逻辑
    1. 参数化标记@pytest.mark.parametrize 会遍历 get_csv_data() 返回的列表,把每行数据拆分为 usernamepasswordassert_msg,传给测试用例。
    2. 数据驱动测试:相当于自动生成多组测试用例,每组用不同的 CSV 数据执行登录流程。

 

四、完整流程与价值

  1. 数据分离:测试数据存在 CSV,改数据不用动代码。
  2. 多组用例:一行 CSV 数据对应一条测试用例,自动执行多组登录场景(如正确 / 错误密码 )。
  3. 复用性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)

四、关键逻辑说明

  1. 打开 Excel 文件
    xlrd.open_workbook("路径"):传入 Excel 文件的绝对路径,加载整个工作簿。

  2. 选择 Sheet

    • sheet_by_index(0):通过下标选 Sheet(0 是第一个 Sheet )。
    • 也可用 sheet_by_name("Sheet1"):按 Sheet 名称选择(更直观 )。
  3. 读取数据

    • sheet.nrows:获取 Sheet 的总行数(包含表头 )。
    • range(1, sheet.nrows):从第 2 行开始遍历(下标从 0 开始,1 对应 Excel 的第 2 行 ),跳过表头。
    • sheet.row_values(i):获取第 i 行的所有单元格值,返回一个列表(如 ["admin", "123", "登录成功"] )。
  4. 数据存储
    把每行数据存入 list1,最终 list1 是二维列表,可用于 pytest.mark.parametrize 实现参数化测试。

五、与自动化测试结合(延伸)

读取 Excel 数据后,可结合 pytest 参数化,让测试用例自动遍历 Excel 数据执行:

import pytest

# (上面的Excel读取代码,封装成 get_excel_data 函数)
def get_excel_data():
    import xlrd
    xls = 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 By

class LoginPage:
    # 元素定位器
    USERNAME_INPUT = (By.ID, "username")
    PASSWORD_INPUT = (By.ID, "password")
    LOGIN_BUTTON = (By.ID, "login-button")

    def __init__(self, driver):
        self.driver = driver

    def 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 By

class WebDriverKeywords:
    def __init__(self, driver):
        self.driver = driver

    def 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 pd

class KeywordEngine:
    def __init__(self, driver):
        self.driver = driver
        self.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):
KeywordParameter1Parameter2Parameter3
open_urlhttp://example.com
input_textidusernameadmin
input_textidpasswordpassword123
click_elementidlogin-button
assert_textWelcome

三、对比分析

维度POMKDT
代码结构按页面组织,每个 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 更适合结构稳定、技术主导的项目。根据你的项目特性选择,能显著提升自动化测试的效率和可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值