Python + Selenium + Pytest 自动化测试实战示例

Python + Selenium + Pytest 自动化测试实战示例

1. 环境准备
# 安装依赖库
pip install selenium pytest pytest-html webdriver-manager
2. 项目结构
automation_framework/
├── conftest.py
├── pages/
│   ├── __init__.py
│   └── login_page.py
├── tests/
│   ├── __init__.py
│   └── test_login.py
├── utils/
│   └── webdriver_factory.py
└── reports/ (自动生成)
3. 核心组件实现

a. 浏览器驱动管理 (utils/webdriver_factory.py)

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager

class WebDriverFactory:
    @staticmethod
    def get_driver(browser="chrome"):
        if browser.lower() == "firefox":
            return webdriver.Firefox(
                executable_path=GeckoDriverManager().install()
            )
        else:
            return webdriver.Chrome(
                executable_path=ChromeDriverManager().install()
            )

b. Page Object 模式 (pages/login_page.py)

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class LoginPage:
    def __init__(self, driver):
        self.driver = driver
        self.url = "https://example.com/login"
        
    def open(self):
        self.driver.get(self.url)
        
    def enter_username(self, username):
        self.driver.find_element(By.ID, "username").send_keys(username)
        
    def enter_password(self, password):
        self.driver.find_element(By.ID, "password").send_keys(password)
        
    def click_login(self):
        self.driver.find_element(By.XPATH, "//button[@type='submit']").click()
        
    def get_error_message(self):
        return WebDriverWait(self.driver, 10).until(
            EC.visibility_of_element_located((By.CLASS_NAME, "error-message"))
        ).text

c. 测试配置 (conftest.py)

import pytest
from utils.webdriver_factory import WebDriverFactory

@pytest.fixture(scope="function")
def browser(request):
    driver = WebDriverFactory.get_driver()
    driver.maximize_window()
    yield driver
    driver.quit()

@pytest.fixture
def login_page(browser):
    page = LoginPage(browser)
    page.open()
    return page
4. 测试用例实现 (tests/test_login.py)
import pytest

class TestLogin:
    @pytest.mark.parametrize("username, password", [
        ("admin", "correct_password"),
        ("test_user", "valid_pass123")
    ])
    def test_valid_login(self, login_page, username, password):
        login_page.enter_username(username)
        login_page.enter_password(password)
        login_page.click_login()
        assert "Dashboard" in login_page.driver.title

    def test_invalid_password(self, login_page):
        login_page.enter_username("admin")
        login_page.enter_password("wrong_pass")
        login_page.click_login()
        assert "Invalid credentials" in login_page.get_error_message()

    def test_empty_fields(self, login_page):
        login_page.click_login()
        error_text = login_page.get_error_message()
        assert "Username is required" in error_text
        assert "Password is required" in error_text
5. 运行测试
# 执行所有测试并生成HTML报告
pytest --html=reports/report.html --self-contained-html
6. 测试报告示例

执行后将在 reports/ 目录生成交互式HTML报告:

  • 包含通过/失败的测试用例统计
  • 每个测试步骤的详细日志
  • 失败用例的屏幕截图
7. 关键设计要点
  1. 分层架构

    • Page Object 封装页面交互
    • 测试用例专注业务逻辑验证
    • 驱动管理独立于测试逻辑
  2. 参数化测试

    @pytest.mark.parametrize("username, password", [
        ("user1", "pass1"),
        ("user2", "pass2")
    ])
    
  3. 智能等待机制

    WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.ID, "element"))
    )
    
  4. 失败自动截图 (在 conftest.py 中添加):

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(item, call):
        outcome = yield
        report = outcome.get_result()
        if report.when == "call" and report.failed:
            driver = item.funcargs["browser"]
            driver.save_screenshot(f"reports/screenshot_{item.name}.png")
    
8. 高级功能扩展
  1. 跨浏览器测试

    pytest --browser=firefox
    
  2. API 集成测试

    def test_login_api(api_client):
        response = api_client.post("/login", 
                                 json={"username": "test", "password": "pass"})
        assert response.status_code == 200
        assert "auth_token" in response.json()
    
  3. 持续集成配置 (Jenkinsfile 示例):

    pipeline {
      agent any
      stages {
        stage('Test') {
          steps {
            sh 'pip install -r requirements.txt'
            sh 'pytest --html=report.html'
          }
          post {
            always {
              publishHTML target: [
                allowMissing: true,
                alwaysLinkToLastBuild: true,
                keepAll: true,
                reportDir: 'reports',
                reportFiles: 'report.html',
                reportName: 'HTML Report'
              ]
            }
          }
        }
      }
    }
    

最佳实践建议

  1. 使用 pytest-xdist 实现并行测试
  2. 敏感数据(如密码)通过 .env 文件管理
  3. 元素定位器统一管理在 locators.py 文件中
  4. 添加 @pytest.mark.flaky(retries=2) 处理偶发失败
  5. 使用 Allure 框架生成更专业的测试报告
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值