【web自动化】-5- fixture集中管理和项目重构

发布于:2025-07-23 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、投标用例设计 

# 定义让前台页面保持自动登录的fixture
@pytest.fixture()
def user_driver():
    driver = webdriver.Chrome()

    driver.get("http://47.107.116.139/fangwei/")

    driver.maximize_window()

    # 创建页面类对象
    page = ReceptionLoginPage(driver)
    # 通过页面类对象调用方法执行脚本
    msg = page.login("admin", "msjy123")
    # 断言实际结果
    print(msg)
    assert msg == "成功登录"
    return driver
  • 如何绕过登录执行投标用例流程,包括投标的正例和反例
  • 在浏览器的驱动第一次执行前台页面登录之后,保持登录状态,在第二次及以上的用例执行投标
定义一个 fixture
  • 完成第一次登录之后进行清除页面缓存
@pytest.fixture()
# 清除缓存的夹具,可以结合第一次登录成功之后的夹具一起结合使用
def clear_deal_page(user_driver):
    user_driver.get("http://47.107.116.139/fangwei/index.php?ctl=deal&id=25070")
  • 在投标用例中使用清除缓存的 fixture

出现的问题:可以正常流程去登录,但是定位点击马上投标的元素超时

  • 元素找不到
  • 问题出现原因:登录成功之后,界面没有立马出现马上投标元素
def test_user_deal_ok(user_driver, clear_deal_page):
    # 投标用例执行
    page = ReceptionLoginPage(user_driver)
    msg = page.pay("msjy123")
    print(msg)
    assert msg == "投标成功!"

def test_user_deal_ok2(user_driver, clear_deal_page):
    # 投标用例执行
    page = ReceptionLoginPage(user_driver)
    msg = page.pay("msjy123")
    print(msg)
    assert msg == "投标成功!"

def test_user_deal_fail(user_driver, clear_deal_page):
    # 投标用例执行
    page = ReceptionLoginPage(user_driver)
    msg = page.pay("msjy1234")
    print(msg)
    assert msg == "支付密码错误"

 

  • 由于直接进入投标界面可以实现流程用例执行
  • 解决方案:
    • 由于登录成功之后自动跳转立即投资界面

    • 所以注释点击马上投标的元素

    • 保持登录的夹具: user_driver 作用域改成 session 级别,保持整个页面的自动登录状态

最终结果:

  • 实现投标用例在第一次登录成功之后,不需要继续进行登录,直接执行投标流程用例即可
  • 作用:保持第一次之后的登录状态来完成投标流程用例执行
# 定义用例脚本执行投标步骤:
def pay(self, password):
    # - 点击马上投标按钮
    # self.find_element(*self.btn_deal_submit).click()
    # - 点击立即投资
    self.find_element(*self.btn_money).click()
    # - 输入支付密码
    self.find_element(*self.ipt_pay_password).send_keys(password)
    # - 点击确定按钮
    self.find_element(*self.btn_pay_submit).click()
    # 获取提示信息的实际结果断言预期结果
    msg = self.find_element(*self.pay_msg, need_wait=True).text
    # - 关闭提示信息弹框
    self.find_element(*self.txt_deal_msg).click()
    # 返回用例执行结果msg
    return msg

1. Fixture 作用域控制(scope="session"

如果 user_driver Fixture 定义时指定了 scope="session"(需补充代码确认,但从场景推断是关键),它会在整个测试会话期间只执行一次

@pytest.fixture(scope="session")  # 关键:作用域为 session,全局共享
def user_driver():
    driver = webdriver.Chrome()
    # 登录逻辑...
    return driver

  • scope="session" 意味着:整个测试运行中,user_driver 只会初始化一次浏览器、执行一次登录,所有依赖它的用例共享同一个浏览器实例,不会重复打开新窗口。

2. 保持登录状态(Cookie/Session 复用)

Web 登录本质是通过 Cookie 或 Session 维持状态:

  • 首次用例执行时,user_driver 完成登录,浏览器会缓存登录态 Cookie。
  • 后续用例复用同一个 driver 实例时,浏览器自带已登录的 Cookie,访问系统时会自动识别登录状态,无需重复登录。

3. 用例依赖共享实例

测试用例通过参数注入 user_driver,所有用例拿到的是同一个浏览器对象

def test_bid_2(user_driver, clear_deal_page):
    # 复用已登录的 user_driver,无需重新打开窗口/登录
    page = ReceptionLoginPage(user_driver)  
    page.pay(...)

因为浏览器实例没销毁,登录状态、页面上下文都被保留,自然 “跳过登录、不新开窗口”。

关键总结

  • Fixture 作用域(session 让浏览器实例全局复用,避免重复初始化。
  • Cookie 持久化 让登录状态在同浏览器实例内自动延续。
  • 最终实现 “一次登录、多例复用”,跳过重复登录和窗口打开流程。

 

在自动化测试流程里,user_driver 结合 clear_deal_page 主要是为了 解决 “登录后页面状态残留” 导致的用例干扰问题

1. 「页面缓存 / 残留状态」的干扰问题

登录后执行投标用例时,页面可能残留上一次操作的状态(比如弹窗未关闭、按钮状态异常、缓存数据未清空):

  • 示例:第一次投标后,页面可能停留在 “支付成功” 提示页,或某些按钮因状态变更无法点击。
  • 影响:后续用例执行时,元素定位会失败(如提示弹窗遮挡按钮),或流程因残留状态报错,导致测试不稳定。

2. clear_deal_page 的核心作用

clear_deal_page 本质是 **“重置页面环境” 的 Fixture**,通常做这些事:

@pytest.fixture()
def clear_deal_page(user_driver):
    # 1. 跳转到统一的“投标初始化页面”
    user_driver.get("http://.../deal?reset=1")  
    # 2. 可能包含清理弹窗、重置按钮状态等操作
    user_driver.execute_script("window.localStorage.clear();")  # 清理本地缓存
    return user_driver

  • 重置页面上下文:强制跳转到一个 “干净” 的投标初始页,确保每次用例执行前,页面状态一致(没有残留弹窗、按钮可点击)。
  • 清理缓存 / 状态:通过 JS 清理 localStoragesessionStorage,或关闭残留提示框,避免上一次用例的缓存数据干扰当前用例。

3. 结合 user_driver 的必要性

user_driver 负责维持登录态(共享浏览器实例、保留 Cookie),但无法解决 “页面级的残留状态”:

  • 只靠 user_driver:登录态是保留了,但页面可能因上一次用例操作变得 “不干净”(比如弹窗未关),导致后续用例定位元素超时 / 失败。
  • 结合 clear_deal_page:在保留登录态的基础上,强制重置页面环境,让每个用例都在 “登录且页面干净” 的状态下执行,既复用了登录(提升效率),又避免了页面残留的干扰(保证稳定)。

二、fixture集中管理 

fixture 的使用形式

  • 用例可以直接调用
  • fixture 夹具之间可以进行关联使用
  • fixture 夹具可以完成任意测试用例脚本的前后置编写
  • 一般情况下不同的用例使用自定义的 fixture 进行使用

为了降低用例脚本和 fixture 夹具的耦合性,将 fixture 进行集中管理

fixture 一般统一管理放置项目中固定 conftest.py 文件中

 

fixture 定位顺序:

  • 先从当前运行的 py 文件开始定位 fixture
  • 其次从同级目录的 py 文件中定位 fixture
  • 再从项目包的目录中开始定位定位 fixture
  • 然后从 conftest.py 文件中开始定位 fixture
  • 最后会从项目所有根目录定位 fixture
  • 以上查找定位 fixture 如果没有对应的夹具,那么程序会报错

三、项目重构

对框架代码进行规划和分类

在项目重构的过程中,之前导入的路径使用的模块,会随着目录结构发生变化而变化,不需要手动修改导包路径

  • testcases
    • 封装完成的用例脚本集中管理
  • commons
    • 项目公共模块集中使用包
  • script
    • 用例的线性脚本
  • data
    • 数据文件相关内容
  • log
    • 日志信息相关内容
  • report
    • 缺陷报告记录的内容
  • conftest.py
    • 存放 fixture 夹具的集中管理

 

 

四、统一管理项目驱动

目的:为了方便后期做兼容性测试,使用不同的浏览器来设计驱动获取

from selenium.webdriver import Chrome, Firefox, Ie, Edge, Safari
自定义函数获取对应的浏览器驱动
def get_webdriver(name: str = "chrome"):
    # 根据调用获取浏览器的实参来返回对应的驱动
    # 将具体浏览器实参名字进行整理
    # 将所有浏览器的名字转化为小写
    # 将所有浏览器的名字中空格去除
    # 再返回驱动的驱动
    name = name.lower()
    name = name.replace(" ", "")
    # print(name)
    # 第一种格式:
    # if name == "chrome":
    #     return Chrome()
    # elif name == "firefox":
    #     return Firefox()
    # 使用match和case关键字匹配驱动
    match name:
        case "chrome":
            return Chrome()
        case "firefox":
            return Firefox()
        case "ie":
            return Ie()
        case "edge":
            return Edge()

# get_webdriver("C hrome")
# get_webdriver("C H  ro  ME")

自定义获取驱动方式重写之后
  • 需要再创建驱动的地方,调用自定义的get_webdriver ("对应浏览器的名字")

五、后台登录的驱动

# 后台登录页面的驱动
@pytest.fixture(scope="session")
def admin_driver():
    driver = get_webdriver()
    driver.get("http://47.107.116.139/fangwei/m.php?m=Public&a=login&")

    # 使用cookie信息
    load_cookies(driver)

    # 如果第一次登录:没有cookie信息那么正常流程登录
    if is_login(driver):
        # 验证码处理
        code = save_code_img(driver)
        # 完成正常登录流程:使用 POM 封装调用脚本执行
        page = BackgroundLoginPage(driver)
        page.login("admin", "msjy123", code)

    yield driver

    # 第一次正常登录之后,用例执行结束之后,完成后置保持 cookie 信息
    save_cookies(driver)

1. 装饰器与 fixture 作用域
@pytest.fixture(scope="session")

  • scope="session":表示该 fixture 的作用域是整个测试会话(session)。也就是说,在一次 pytest 测试运行过程中,这个 admin_driver 夹具只会被初始化一次,然后在所有需要它的测试用例中复用,测试会话结束时才会执行其后置清理逻辑(yield 之后的代码)。这样可以提升测试效率,比如这里用于保持后台登录状态,避免重复登录操作。

 

2. 驱动初始化与页面访问

driver = get_webdriver()
driver.get("http://47.107.116.139/fangwei/m.php?m=Public&a=login&")

  • get_webdriver():调用了一个自定义的函数(这个函数用于根据配置获取对应的浏览器驱动实例,比如 Chrome、Firefox 等浏览器的驱动,方便进行兼容性测试 ),获取到浏览器驱动对象 driver,后续用这个驱动来操作浏览器。
  • driver.get(...):使用获取到的浏览器驱动,打开指定的后台登录页面 URL,让浏览器跳转到对应的登录界面,为后续登录操作做准备。

 

3. Cookie 相关操作

# 使用 cookie 信息
load_cookies(driver)

  • load_cookies(driver):调用自定义函数 load_cookies,作用是尝试从某个地方加载之前保存的 Cookie 信息,并将其注入到当前的浏览器驱动 driver 中。这样做的目的是,如果之前有成功登录过并保存了 Cookie,那么通过加载这些 Cookie,可以直接保持登录状态,无需再次输入账号密码等进行登录,提升测试执行效率。

 

4. 登录流程处理(条件判断)

# 如果第一次登录:没有 cookie 信息那么正常流程登录
if is_login(driver):
    # 验证码处理
    code = save_code_img(driver)
    # 完成正常登录流程:使用 POM 封装调用脚本执行
    page = BackgroundLoginPage(driver)
    page.login("admin", "msjy123", code)

  • is_login(driver):调用自定义函数 is_login,用于判断当前浏览器驱动 driver 对应的页面是否处于已登录状态。可能的实现逻辑比如检查页面中是否存在登录后的特定元素(如用户名显示、登录状态标识等 ),或者根据 Cookie 信息判断会话是否有效。如果返回 True,说明需要执行正常的登录流程(一般是首次登录或者 Cookie 失效等情况 )。
  • save_code_img(driver):调用自定义函数 save_code_img,用于处理登录页面的验证码。可能的操作包括截取验证码图片、识别验证码内容(如果结合了验证码识别技术,比如 OCR 等 ),并返回验证码的文本内容 code,以便后续登录时使用。
  • BackgroundLoginPage(driver):这里使用了页面对象模型(POM,Page Object Model )的设计模式,创建一个 BackgroundLoginPage 类的实例 page,并将浏览器驱动 driver 传入。POM 模式把页面的元素定位和操作方法封装到对应的页面类中,便于代码维护和复用。
  • page.login("admin", "msjy123", code):调用 BackgroundLoginPage 类中封装的 login 方法,传入用户名 admin、密码 msjy123 和前面获取到的验证码 code,执行实际的登录操作,模拟用户在页面上输入账号、密码、验证码并提交登录的流程。

 

5. fixture 的 yield 关键字

yield driver

  • yield 是 pytest fixture 中用于分隔前置操作和后置操作的关键字。yield 之前的代码属于前置准备逻辑,执行到 yield 时,会暂停当前 fixture 的执行,将 driver 对象返回给调用它的测试用例使用。当所有依赖该 fixture 的测试用例执行完毕后,会回到这个 fixture,继续执行 yield 之后的代码,也就是后置清理 / 保存操作。

 

6. 后置保存 Cookie 操作

# 第一次正常登录之后,用例执行结束之后,完成后置保持 cookie 信息
save_cookies(driver)

  • save_cookies(driver):调用自定义函数 save_cookies,在测试用例执行完毕后,将当前浏览器驱动 driver 中的 Cookie 信息保存起来(比如保存到文件、数据库等 )。这样,下次再执行测试时,就可以通过前面的 load_cookies 函数加载这些 Cookie,实现免登录或者保持登录状态的效果,提升后续测试的效率,也能模拟实际用户的会话保持场景。

 


网站公告

今日签到

点亮在社区的每一天
去签到