You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python+Selenium+Pytest如何复用登录逻辑及实现登录失败跳过用例

Pytest+Selenium 登录逻辑复用与失败跳过最佳实践

你最初考虑的在每个业务测试场景文件中单独调用test_login的方案不推荐。Pytest的测试用例设计原则是单用例独立可执行,跨用例直接调用会导致执行顺序强耦合、失败链路难追溯、测试报告统计失真,这类通用前置依赖的标准处理方式是使用Pytest的fixture机制。


实现逻辑

  • 将登录逻辑从测试用例中抽离,封装为公共可复用的fixture,按测试效率需求设置对应作用域,所有需要登录的用例自动依赖该fixture完成前置操作,无需重复编写登录代码。
  • 在登录fixture中增加异常捕获,一旦登录流程执行失败、登录态校验不通过,直接触发pytest跳过逻辑,所有依赖登录状态的后续用例自动标记为跳过,不会执行无效的业务步骤。
  • 保留原有test_authentication作为独立的登录功能校验用例,不再承担其他用例的前置职责。

具体代码改造

1. 修改conftest.py,新增公共登录fixture

把原本写在test_authentication中的登录逻辑迁移到conftest中,作为全局可用的fixture,和现有webdriver fixture保持一致的class级作用域,同一个测试类下仅需登录一次,减少重复操作提升执行速度:

# conftest.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

@pytest.fixture(scope='class')
def webdriver(request):
    driver = webdriver.Firefox()
    driver.maximize_window()
    request.cls.driver = driver
    yield driver
    driver.quit()

@pytest.fixture(scope="class")
def login(webdriver, request):
    driver = webdriver
    try:
        driver.get('https://url.com/')
        # 替换硬等待为显式等待,降低页面加载波动导致的用例不稳定问题
        WebDriverWait(driver, 15).until(
            EC.frame_to_be_available_and_switch_to_it("gsft_main")
        )
        # 输入账号密码提交登录
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "user_name"))
        ).send_keys("username")
        driver.find_element(By.ID, "user_password").send_keys("pass")
        driver.find_element(By.ID, "sysverb_login").click()
        
        # 切回默认页面上下文,校验登录结果
        driver.switch_to.default_content()
        user_header = WebDriverWait(driver, 20).until(
            EC.presence_of_element_located((By.XPATH, '/html/body/div[5]/div/div/header/div[1]/div/div[2]/div/div[2]/div/button/div/span[1]'))
        )
        assert user_header.text == "System Administrator"
        request.cls.is_logged_in = True
        yield
    except Exception as e:
        # 登录失败时直接跳过所有依赖该fixture的用例
        pytest.skip(f"登录执行失败,跳过后续依赖用例,失败原因:{str(e)}")

2. 调整base_test.py,区分不同前置依赖的测试基类

# base_test.py
import pytest

# 所有需要登录态的业务测试类继承该基类,自动完成驱动初始化+登录前置
@pytest.mark.usefixtures("webdriver", "login")
class BaseLoggedInTest:
    pass

# 不需要登录态的测试类(比如登录页本身的测试)继承该基类
@pytest.mark.usefixtures("webdriver")
class BaseTest:
    pass

3. 简化原有登录测试用例

# test_login.py
from base_test import BaseTest

class TestLogin(BaseTest):
    def test_authentication(self, login):
        # 直接依赖login fixture完成登录流程校验,无需重复编写登录代码
        assert self.is_logged_in == True

4. 后续业务用例写法

后续所有需要登录的测试场景(创建事件、创建变更记录等),只需要继承BaseLoggedInTest,类执行前会自动完成登录,不需要编写任何登录相关代码:

# test_incident.py
from base_test import BaseLoggedInTest

class TestCreateIncident(BaseLoggedInTest):
    def test_create_and_save_incident(self):
        # 进入方法时已经完成登录,直接编写创建事件的业务逻辑即可
        driver = self.driver
        # 业务逻辑省略
        pass
# test_change.py
from base_test import BaseLoggedInTest

class TestCreateChange(BaseLoggedInTest):
    def test_create_and_save_change(self):
        # 直接编写创建变更记录的业务逻辑
        pass

配置说明

  • 如果需要调整登录的复用粒度,只需要修改login fixture的scope参数:设置为function时每个测试用例执行前都会重新登录,设置为session时整个测试执行周期仅登录一次,可根据实际测试场景选择。
  • 原有代码中大量的time.sleep硬等待全部替换为Selenium显式等待,可大幅降低因页面加载速度波动导致的用例随机失败问题。
  • 登录失败时触发的pytest.skip()会直接终止当前fixture的执行,所有依赖该fixture的用例都会被标记为跳过,不会出现未登录状态下执行业务步骤导致的一连串无意义失败。

内容的提问来源于stack exchange,提问作者anfield

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 21:45:46