1. 项目背景与测试目标
最近接手了一个客户升级版的自动化测试项目,需要为白月SMS系统的客户管理模块构建完整的自动化测试方案。这个系统是一个典型的企业客户关系管理系统,客户管理作为核心功能模块,其稳定性和可靠性直接影响业务运营。
选择Selenium+Pytest技术栈主要基于以下几点考虑:
- 系统采用传统Web架构,前端基于HTML+CSS+JS,Selenium对这类技术栈支持最为成熟
- Pytest作为Python生态中最强大的测试框架,提供了丰富的插件生态(如pytest-html生成报告、pytest-xdist并行测试)
- 客户要求测试脚本具备良好的可维护性和可扩展性,Python语言的简洁语法和丰富库生态非常适合
测试范围聚焦在客户管理的三个核心场景:
- 客户添加(包含必填项验证)
- 客户信息编辑
- 客户删除
提示:在Web自动化测试中,建议从核心业务流程开始构建测试用例,再逐步覆盖边界条件和异常场景,这样可以在有限时间内最大化测试覆盖率。
2. 测试环境搭建与框架设计
2.1 环境准备
基础环境配置:
bash复制# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# 安装核心依赖
pip install selenium pytest pytest-html
浏览器驱动管理方案:
- 方案1:手动下载对应版本的ChromeDriver并配置PATH
- 方案2:使用webdriver-manager自动管理(推荐)
python复制# 安装webdriver-manager
pip install webdriver-manager
# 在conftest.py中配置自动驱动管理
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
@pytest.fixture(scope="session")
def browser():
driver = webdriver.Chrome(ChromeDriverManager().install())
yield driver
driver.quit()
2.2 框架设计
采用分层架构提升可维护性:
code复制project/
├── pages/ # 页面对象模型
│ ├── login_page.py
│ └── customer_page.py
├── tests/ # 测试用例
│ └── test_customer.py
├── utils/ # 工具类
│ ├── logger.py
│ └── config.py
└── conftest.py # pytest配置
关键设计原则:
- 页面对象模式(POM):将页面元素定位和操作封装成类方法
- 数据驱动:使用@pytest.mark.parametrize管理测试数据
- 夹具共享:通过conftest.py共享browser等fixture
- 异常处理:为网络延迟、元素加载等场景添加显式等待
3. 测试用例实现详解
3.1 客户添加功能测试
以Customer_01用例为例,完整实现如下:
python复制import pytest
from pages.customer_page import CustomerPage
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TestCustomerManagement:
@pytest.mark.parametrize("name,phone,address,expected", [
("", "13800138000", "北京", "客户名不能为空"), # 用例1
("张三", "", "上海", "联系电话不能为空"), # 补充用例
])
def test_add_customer_validation(self, browser, name, phone, address, expected):
customer_page = CustomerPage(browser)
customer_page.open_add_dialog()
# 执行测试步骤
customer_page.enter_customer_name(name)
customer_page.enter_phone(phone)
customer_page.enter_address(address)
customer_page.click_create_button()
# 验证结果
alert = WebDriverWait(browser, 5).until(
EC.visibility_of_element_located(customer_page.ALERT_LOCATOR)
)
assert expected in alert.text
页面对象封装示例(customer_page.py):
python复制from selenium.webdriver.common.by import By
class CustomerPage:
# 元素定位器
ADD_BUTTON = (By.ID, "add-customer")
NAME_INPUT = (By.NAME, "customerName")
PHONE_INPUT = (By.CSS_SELECTOR, "input[name='phone']")
CREATE_BUTTON = (By.XPATH, "//button[text()='创建']")
ALERT_LOCATOR = (By.CLASS_NAME, "el-alert__content")
def __init__(self, driver):
self.driver = driver
def open_add_dialog(self):
self.driver.find_element(*self.ADD_BUTTON).click()
def enter_customer_name(self, name):
self.driver.find_element(*self.NAME_INPUT).send_keys(name)
# 其他操作方法...
3.2 客户编辑与删除测试
编辑测试关键点:
python复制def test_edit_customer(self, browser):
customer_page = CustomerPage(browser)
original_name = customer_page.get_first_customer_name()
# 执行编辑操作
customer_page.edit_first_customer(name="更新名称")
# 验证更新结果
updated_name = customer_page.get_first_customer_name()
assert updated_name == "更新名称"
assert updated_name != original_name
删除测试注意事项:
python复制def test_delete_customer(self, browser):
customer_page = CustomerPage(browser)
initial_count = customer_page.get_customer_count()
# 执行删除
customer_page.delete_first_customer()
# 确认删除后数量减少
WebDriverWait(browser, 5).until(
lambda d: customer_page.get_customer_count() == initial_count - 1
)
重要提示:对于删除这类危险操作,建议:
- 在测试环境中操作
- 添加确认对话框处理逻辑
- 考虑使用数据库快照恢复测试数据
4. 测试执行与报告生成
4.1 执行配置
pytest.ini配置文件示例:
ini复制[pytest]
addopts =
--html=reports/report.html
--self-contained-html
--capture=sys
-v
markers =
smoke: 冒烟测试
regression: 回归测试
常用执行命令:
bash复制# 运行全部测试
pytest
# 运行标记为smoke的测试
pytest -m smoke
# 并行运行测试(需要pytest-xdist)
pytest -n 4
4.2 测试报告优化
通过conftest.py添加截图功能:
python复制@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
browser = item.funcargs["browser"]
screenshot = browser.get_screenshot_as_base64()
report.extra = [pytest_html.extras.image(screenshot)]
报告增强技巧:
- 添加环境信息:
python复制def pytest_configure(config):
config._metadata.update({
"测试环境": "STG",
"浏览器": "Chrome 103"
})
- 自定义报告标题:
python复制def pytest_html_report_title(report):
report.title = "白月SMS系统自动化测试报告"
5. 常见问题与解决方案
5.1 元素定位问题
典型报错:NoSuchElementException
解决方案:
- 使用显式等待替代隐式等待
python复制from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamic-element"))
)
- 更健壮的定位策略:
- 优先使用ID、name等稳定属性
- CSS Selector比XPath性能更好
- 避免使用绝对路径和索引定位
5.2 测试数据管理
推荐方案:
- 使用JSON或YAML文件管理测试数据
python复制import json
with open("test_data.json") as f:
test_data = json.load(f)
@pytest.mark.parametrize("data", test_data["customers"])
def test_add_customer(data):
...
- 数据库夹具示例:
python复制import pytest
from models import Customer, db
@pytest.fixture
def sample_customer():
customer = Customer(name="测试客户", phone="13800138000")
db.session.add(customer)
db.session.commit()
yield customer
db.session.delete(customer)
db.session.commit()
5.3 跨浏览器测试方案
conftest.py配置多浏览器支持:
python复制def pytest_addoption(parser):
parser.addoption("--browser", action="store", default="chrome")
@pytest.fixture(scope="session")
def browser(request):
browser_name = request.config.getoption("--browser")
if browser_name == "firefox":
driver = webdriver.Firefox()
elif browser_name == "edge":
driver = webdriver.Edge()
else:
driver = webdriver.Chrome()
yield driver
driver.quit()
执行命令:
bash复制pytest --browser=firefox
pytest --browser=edge
6. 项目优化方向
- 测试数据工厂
使用Factory Boy创建测试数据:
python复制import factory
from models import Customer
class CustomerFactory(factory.Factory):
class Meta:
model = Customer
name = factory.Faker("name")
phone = factory.Faker("phone_number")
- API+UI混合测试
python复制def test_ui_consistency_with_api():
# 通过API创建客户
api_response = create_customer_via_api(name="API客户")
# 通过UI验证
customer_page.search(api_response["id"])
assert customer_page.get_customer_name() == api_response["name"]
- 视觉回归测试
集成Applitools或Screenshot断言:
python复制from selenium_screenshot import assert_screenshot
def test_ui_layout(browser):
browser.get("/customers")
assert_screenshot(browser, "customer_page")
- 性能监控
python复制import time
def test_add_customer_performance(browser):
start = time.time()
# 执行添加操作
end = time.time()
assert end - start < 2.0 # 响应时间应小于2秒
在实际项目中,我通常会先构建核心功能的冒烟测试套件,确保基本功能正常后再逐步补充边界条件测试。对于客户管理这类核心模块,建议至少保持80%以上的代码覆盖率,关键业务路径要达到100%覆盖。