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
相关产品推荐
相关产品推荐

