Allure 与 pytest 集成详解
1. 什么是 Allure 与 pytest 集成
1.1 集成概述
Allure 与 pytest 集成是指将 Allure 测试报告框架与 pytest 测试框架无缝结合,使 pytest 测试用例的执行结果能够自动生成美观、详细的 Allure 测试报告。这种集成让测试人员可以:
- 自动生成企业级测试报告
- 查看详细的测试步骤和附件
- 追踪测试历史趋势
- 方便地分享测试结果给团队
1.2 为什么需要集成
没有集成的情况:
# 运行 pytest 测试
pytest test_example.py -v
# 输出结果
======================== test session starts ==========================
platform win32 -- Python 3.9.0, pytest-7.0.0
collected 3 items
test_example.py::test_login PASSED [ 33%]
test_example.py::test_create_user PASSED [ 66%]
test_example.py::test_delete_user FAILED [100%]
======================== FAILURES ==========================
test_delete_user FAILED
AssertionError: assert False
问题:
- 报告不够直观,只是简单的文本输出
- 无法看到详细的测试步骤
- 无法附加截图、日志等附件
- 无法查看历史趋势
- 不适合向领导汇报
集成 Allure 后:
# 运行测试并生成 Allure 报告
pytest test_example.py --alluredir=./allure-results
allure serve ./allure-results
# 生成一个美观的 HTML 报告,包含:
# - 详细的测试步骤
# - 测试截图
# - 测试日志
# - 历史趋势图
# - 测试分类和标签
# - 环境信息
优势:
- 美观的 HTML 报告,适合向领导汇报
- 详细的测试步骤,方便定位问题
- 支持截图、日志等附件
- 历史趋势分析
- 测试分类和标签管理
- 团队协作友好
1.3 集成的工作原理
pytest 执行测试用例
↓
allure-pytest 插件收集测试结果
↓
生成 Allure 结果数据(JSON/XML 格式)
↓
保存到 allure-results 目录
↓
使用 Allure 命令行工具生成 HTML 报告
↓
在浏览器中查看美观的报告
1.4 集成的核心组件
- allure-pytest:pytest 的 Allure 适配器插件
- Allure 命令行工具:用于生成和查看报告
- pytest:测试框架本身
- 测试代码:使用 Allure 装饰器和 API 的测试用例
2. 环境准备和安装
2.1 系统要求
Python 版本:
- Python 3.6 或更高版本
- 推荐使用 Python 3.8+
pytest 版本:
- pytest 5.0 或更高版本
- 推荐使用 pytest 7.0+
操作系统:
- Windows
- macOS
- Linux
2.2 安装 pytest
基本安装:
pip install pytest
指定版本安装:
# 安装特定版本
pip install pytest==7.4.0
# 安装最新版本
pip install pytest --upgrade
验证安装:
pytest --version
输出示例:
pytest 7.4.0
2.3 安装 allure-pytest
基本安装:
pip install allure-pytest
指定版本安装:
# 安装特定版本
pip install allure-pytest==2.13.2
# 安装最新版本
pip install allure-pytest --upgrade
验证安装:
pip show allure-pytest
输出示例:
Name: allure-pytest
Version: 2.13.2
Summary: Allure pytest integration
Location: C:UsersAdministratorAppDataLocalProgramsPythonPython39libsite-packages
2.4 安装 Allure 命令行工具
2.4.1 Windows 安装
方法 1:使用 Scoop 安装(推荐)
# 1. 先安装 Scoop(如果没有)
# 在 PowerShell 中执行(以管理员身份)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
irm get.scoop.sh | iex
# 2. 使用 Scoop 安装 Allure
scoop install allure
# 3. 验证安装
allure --version
方法 2:手动安装
# 1. 下载 Allure
# 访问 https://github.com/allure-framework/allure2/releases
# 下载 allure-2.13.2.zip(或最新版本)
# 2. 解压到某个目录,例如 C:allure
# 3. 将 C:allurebin 添加到系统环境变量 PATH 中
# 右键"此电脑" -> "属性" -> "高级系统设置" -> "环境变量"
# 在"系统变量"中找到 Path,点击"编辑",添加 C:allurebin
# 4. 验证安装
allure --version
2.4.2 macOS 安装
使用 Homebrew 安装:
brew install allure
验证安装:
allure --version
2.4.3 Linux 安装
Ubuntu/Debian:
# 添加仓库
sudo apt-add-repository ppa:qameta/allure
sudo apt-get update
# 安装
sudo apt-get install allure
或者使用 Snap:
sudo snap install allure --classic
验证安装:
allure --version
2.5 验证完整安装
创建测试文件 test_installation.py:
import pytest
import allure
def test_allure_installed():
"""验证 Allure 已正确安装"""
assert True
def test_pytest_installed():
"""验证 pytest 已正确安装"""
assert True
运行测试:
pytest test_installation.py --alluredir=./allure-results -v
生成报告:
allure serve ./allure-results
如果一切正常:
- pytest 会成功运行测试
- 会在
./allure-results目录生成结果文件 allure serve会在浏览器中打开报告
3. 基本集成步骤
3.1 最简单的集成示例
让我们从一个最简单的例子开始,了解如何将 Allure 与 pytest 集成。
步骤 1:创建测试文件
创建 test_simple.py:
import pytest
import allure
def test_addition():
"""测试加法"""
assert 1 + 1 == 2
def test_subtraction():
"""测试减法"""
assert 5 - 3 == 2
def test_multiplication():
"""测试乘法"""
assert 2 * 3 == 6
步骤 2:运行测试并生成 Allure 结果
pytest test_simple.py --alluredir=./allure-results
说明:
--alluredir=./allure-results:指定 Allure 结果数据的保存目录- pytest 会自动使用 allure-pytest 插件收集测试结果
- 结果数据会以 JSON 格式保存在
./allure-results目录中
步骤 3:生成并查看报告
allure serve ./allure-results
说明:
allure serve会:- 生成临时的 HTML 报告
- 启动本地服务器
- 在默认浏览器中打开报告
- 报告地址通常是
http://localhost:随机端口
步骤 4:查看报告
报告界面包含:
- Overview(概览):测试执行的整体情况
- Suites(套件):按测试套件查看
- Graphs(图表):测试结果的可视化图表
- Behaviors(行为):按行为分类查看
- Packages(包):按包/模块查看
3.2 生成静态报告
除了使用 allure serve 查看临时报告,还可以生成静态 HTML 报告:
# 生成静态报告
allure generate ./allure-results -o ./allure-report --clean
# 查看报告(需要手动打开)
# Windows: 在文件管理器中打开 allure-report/index.html
# macOS: open allure-report/index.html
# Linux: xdg-open allure-report/index.html
参数说明:
-o ./allure-report:指定报告输出目录--clean:清理输出目录(如果已存在)
优势:
- 可以保存报告文件
- 可以分享给其他人
- 可以部署到 Web 服务器
3.3 完整的集成流程示例
项目结构:
myproject/
├── tests/
│ ├── __init__.py
│ ├── test_login.py
│ └── test_user.py
├── allure-results/ # Allure 结果数据(自动生成)
├── allure-report/ # Allure 报告(自动生成)
└── pytest.ini # pytest 配置文件
测试文件 tests/test_login.py:
import pytest
import allure
@allure.feature("用户管理")
@allure.story("用户登录")
class TestLogin:
"""用户登录测试类"""
@allure.title("测试管理员登录")
def test_admin_login(self):
"""测试管理员登录"""
with allure.step("打开登录页面"):
print("打开登录页面")
with allure.step("输入用户名和密码"):
username = "admin"
password = "admin123"
print(f"输入用户名: {username}")
print(f"输入密码: {password}")
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录成功"):
assert True
@allure.title("测试普通用户登录")
def test_user_login(self):
"""测试普通用户登录"""
with allure.step("打开登录页面"):
print("打开登录页面")
with allure.step("输入用户名和密码"):
username = "user"
password = "user123"
print(f"输入用户名: {username}")
print(f"输入密码: {password}")
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录成功"):
assert True
运行测试:
# 1. 运行测试并生成 Allure 结果
pytest tests/ --alluredir=./allure-results -v
# 2. 生成并查看报告
allure serve ./allure-results
4. pytest 配置文件集成
4.1 在 pytest.ini 中配置
创建 pytest.ini 文件:
[pytest]
# 基本配置
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
# Allure 配置
addopts =
--alluredir=./allure-results
-v
--tb=short
# 标记
markers =
smoke: 冒烟测试
regression: 回归测试
slow: 慢速测试
使用配置:
# 直接运行 pytest,会自动使用配置文件中的设置
pytest
# 不需要每次都指定 --alluredir
# pytest 会自动使用 pytest.ini 中的配置
4.2 在 pyproject.toml 中配置
创建 pyproject.toml 文件:
[tool.pytest.ini_options]
# 基本配置
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
# Allure 配置
addopts = [
"--alluredir=./allure-results",
"-v",
"--tb=short"
]
# 标记
markers = [
"smoke: 冒烟测试",
"regression: 回归测试",
"slow: 慢速测试"
]
使用配置:
# 直接运行 pytest
pytest
4.3 在 conftest.py 中配置
创建 conftest.py 文件:
import pytest
import allure
import os
def pytest_configure(config):
"""pytest 配置钩子"""
# 确保 allure-results 目录存在
allure_dir = "./allure-results"
os.makedirs(allure_dir, exist_ok=True)
# 配置 Allure 环境信息
config.option.allure_report_dir = allure_dir
@pytest.fixture(scope="session", autouse=True)
def configure_allure_environment():
"""配置 Allure 环境信息"""
environment = {
"OS": os.name,
"Python": os.sys.version,
"Pytest": pytest.__version__,
}
# 写入环境信息到 allure-results 目录
allure_dir = "./allure-results"
os.makedirs(allure_dir, exist_ok=True)
env_file = os.path.join(allure_dir, "environment.properties")
with open(env_file, "w", encoding="utf-8") as f:
for key, value in environment.items():
f.write(f"{key}={value}n")
yield
4.4 配置文件优先级
配置的优先级(从高到低):
- 命令行参数
pytest.ini或pyproject.tomlconftest.py中的配置- 默认配置
示例:
# 命令行参数优先级最高
pytest --alluredir=./custom-results
# 即使 pytest.ini 中配置了 --alluredir=./allure-results
# 也会使用命令行中的 ./custom-results
5. Allure 装饰器与 pytest 集成
5.1 @allure.title – 设置测试标题
基本用法:
import pytest
import allure
@allure.title("用户登录测试")
def test_login():
"""测试用户登录功能"""
assert True
@allure.title("创建新用户")
def test_create_user():
"""测试创建用户功能"""
assert True
动态标题:
import pytest
import allure
@pytest.mark.parametrize("username", ["admin", "user", "guest"])
@allure.title("测试用户 {username} 的登录功能")
def test_login_with_username(username):
"""使用参数化测试,标题中包含参数"""
assert username in ["admin", "user", "guest"]
在测试类中使用:
import pytest
import allure
@allure.feature("用户管理")
class TestUser:
"""用户管理测试类"""
@allure.title("测试管理员登录")
def test_admin_login(self):
"""测试管理员登录"""
assert True
@allure.title("测试普通用户登录")
def test_user_login(self):
"""测试普通用户登录"""
assert True
5.2 @allure.description – 添加测试描述
使用装饰器参数:
import allure
@allure.description("""
这是一个详细的测试描述:
1. 测试用户登录功能
2. 验证用户名和密码
3. 检查登录后的跳转
""")
def test_login():
assert True
使用文档字符串:
import allure
@allure.description
def test_login():
"""
测试用户登录功能
前置条件:
- 用户已注册
- 数据库连接正常
测试步骤:
1. 打开登录页面
2. 输入用户名和密码
3. 点击登录按钮
预期结果:
- 登录成功
- 跳转到首页
"""
assert True
5.3 @allure.step – 定义测试步骤
基本用法:
import allure
@allure.step("打开登录页面")
def open_login_page():
"""打开登录页面"""
print("正在打开登录页面...")
return True
@allure.step("输入用户名: {username}")
def input_username(username):
"""输入用户名"""
print(f"正在输入用户名: {username}")
return True
@allure.step("点击登录按钮")
def click_login_button():
"""点击登录按钮"""
print("正在点击登录按钮...")
return True
def test_login():
"""测试登录流程"""
open_login_page()
input_username("admin")
click_login_button()
assert True
使用上下文管理器:
import allure
def test_login_with_steps():
"""测试登录流程(在测试函数中定义步骤)"""
with allure.step("打开登录页面"):
print("打开登录页面")
with allure.step("输入用户名和密码"):
username = "admin"
password = "123456"
print(f"输入用户名: {username}")
print(f"输入密码: {password}")
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录结果"):
assert True
步骤嵌套:
import allure
@allure.step("准备测试数据")
def prepare_data():
"""准备测试数据"""
with allure.step("连接数据库"):
print("连接数据库")
with allure.step("查询用户信息"):
print("查询用户信息")
with allure.step("清理临时数据"):
print("清理临时数据")
def test_with_nested_steps():
"""测试嵌套步骤"""
prepare_data()
assert True
5.4 @allure.severity – 设置测试优先级
优先级级别:
import allure
import pytest
@allure.severity(allure.severity_level.BLOCKER)
def test_critical_login():
"""阻塞级别测试(最高优先级)"""
assert True
@allure.severity(allure.severity_level.CRITICAL)
def test_important_feature():
"""严重级别测试"""
assert True
@allure.severity(allure.severity_level.NORMAL)
def test_normal_feature():
"""正常级别测试(默认)"""
assert True
@allure.severity(allure.severity_level.MINOR)
def test_minor_feature():
"""次要级别测试"""
assert True
@allure.severity(allure.severity_level.TRIVIAL)
def test_trivial_feature():
"""轻微级别测试(最低优先级)"""
assert True
按优先级运行测试:
# 只运行阻塞级别的测试
pytest test_example.py --alluredir=./allure-results -s -v --allure-severities=blocker
# 运行阻塞和严重级别的测试
pytest test_example.py --alluredir=./allure-results -s -v --allure-severities=blocker,critical
5.5 @allure.feature 和 @allure.story – 功能分类
功能分类示例:
import allure
@allure.feature("用户管理")
@allure.story("用户注册")
def test_user_register():
"""用户注册"""
assert True
@allure.feature("用户管理")
@allure.story("用户登录")
def test_user_login():
"""用户登录"""
assert True
@allure.feature("用户管理")
@allure.story("用户注销")
def test_user_logout():
"""用户注销"""
assert True
@allure.feature("订单管理")
@allure.story("创建订单")
def test_create_order():
"""创建订单"""
assert True
@allure.feature("订单管理")
@allure.story("查看订单")
def test_view_order():
"""查看订单"""
assert True
按功能或故事运行测试:
# 只运行"用户管理"功能的测试
pytest test_example.py --alluredir=./allure-results -s -v --allure-features="用户管理"
# 只运行"用户登录"故事的测试
pytest test_example.py --alluredir=./allure-results -s -v --allure-stories="用户登录"
5.6 组合使用多个装饰器
完整示例:
import allure
import pytest
@allure.feature("用户管理")
@allure.story("用户登录")
@allure.severity(allure.severity_level.BLOCKER)
@allure.title("测试管理员登录功能")
@allure.description("""
测试管理员登录功能:
1. 输入正确的管理员账号和密码
2. 验证登录成功
3. 检查用户权限
""")
def test_admin_login():
"""测试管理员登录"""
with allure.step("打开登录页面"):
print("打开登录页面")
with allure.step("输入管理员账号和密码"):
username = "admin"
password = "admin123"
print(f"输入用户名: {username}")
print(f"输入密码: {password}")
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录成功"):
assert True
6. pytest fixture 与 Allure 集成
6.1 在 fixture 中使用 Allure 步骤
示例 1:基本 fixture:
import pytest
import allure
@pytest.fixture
def login_user():
"""登录用户 fixture"""
with allure.step("准备用户数据"):
username = "admin"
password = "admin123"
with allure.step("执行登录操作"):
print(f"用户 {username} 登录中...")
# 模拟登录逻辑
user_info = {"username": username, "logged_in": True}
yield user_info
with allure.step("清理登录状态"):
print("清理登录状态")
def test_with_login_fixture(login_user):
"""使用登录 fixture 的测试"""
assert login_user["logged_in"] is True
assert login_user["username"] == "admin"
示例 2:带参数的 fixture:
import pytest
import allure
@pytest.fixture
def user_data(request):
"""用户数据 fixture"""
username = request.param
with allure.step(f"准备用户 {username} 的数据"):
user_info = {
"username": username,
"email": f"{username}@example.com",
"role": "admin" if username == "admin" else "user"
}
return user_info
@pytest.mark.parametrize("user_data", ["admin", "user", "guest"], indirect=True)
def test_user_data(user_data):
"""测试用户数据"""
assert user_data["username"] is not None
assert "@example.com" in user_data["email"]
6.2 fixture 中的附件添加
示例:在 fixture 中添加截图:
import pytest
import allure
from selenium import webdriver
@pytest.fixture(scope="function")
def driver():
"""WebDriver fixture"""
driver = webdriver.Chrome()
with allure.step("初始化浏览器"):
driver.maximize_window()
screenshot = driver.get_screenshot_as_png()
allure.attach(
screenshot,
name="浏览器初始化",
attachment_type=allure.attachment_type.PNG
)
yield driver
# 如果测试失败,自动截图
if hasattr(pytest, 'current_test_failed') and pytest.current_test_failed:
with allure.step("测试失败,保存截图"):
screenshot = driver.get_screenshot_as_png()
allure.attach(
screenshot,
name="失败截图",
attachment_type=allure.attachment_type.PNG
)
driver.quit()
def test_login_with_driver(driver):
"""使用 driver fixture 的测试"""
driver.get("https://example.com/login")
assert "login" in driver.current_url.lower()
6.3 使用 pytest hooks 集成 Allure
在 conftest.py 中使用 hooks:
import pytest
import allure
def pytest_runtest_setup(item):
"""测试设置钩子"""
# 在测试开始前执行
allure.dynamic.description_html("""
<h3>测试开始</h3>
<p>这是动态添加的 HTML 描述</p>
""")
def pytest_runtest_teardown(item, nextitem):
"""测试清理钩子"""
# 在测试结束后执行
pass
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""生成测试报告钩子"""
outcome = yield
rep = outcome.get_result()
# 如果测试失败,添加附件
if rep.when == "call" and rep.failed:
allure.attach(
f"测试失败: {rep.longrepr}",
name="失败信息",
attachment_type=allure.attachment_type.TEXT
)
7. pytest 参数化与 Allure 集成
7.1 基本参数化
示例 1:简单参数化:
import pytest
import allure
@pytest.mark.parametrize("a, b, expected", [
(1, 2, 3),
(3, 4, 7),
(5, 6, 11),
])
@allure.title("测试加法: {a} + {b} = {expected}")
def test_addition(a, b, expected):
"""参数化测试加法"""
with allure.step(f"计算 {a} + {b}"):
result = a + b
allure.attach(
f"输入: a={a}, b={b}n结果: {result}n预期: {expected}",
name="计算过程",
attachment_type=allure.attachment_type.TEXT
)
assert result == expected
示例 2:参数化与 feature/story 结合:
import pytest
import allure
@allure.feature("用户管理")
@allure.story("用户登录")
@pytest.mark.parametrize("username, password, expected", [
("admin", "admin123", True),
("user", "user123", True),
("guest", "wrong", False),
])
@allure.title("测试用户 {username} 登录")
def test_login_parametrize(username, password, expected):
"""参数化测试登录"""
with allure.step(f"尝试使用 {username} 登录"):
# 模拟登录逻辑
login_success = (username, password) in [
("admin", "admin123"),
("user", "user123")
]
allure.attach(
f"用户名: {username}n密码: {password}n登录成功: {login_success}",
name="登录信息",
attachment_type=allure.attachment_type.TEXT
)
assert login_success == expected
7.2 参数化与动态标题
示例:
import pytest
import allure
@pytest.mark.parametrize("user_type", ["admin", "user", "guest"])
def test_user_permissions(user_type):
"""测试不同用户类型的权限"""
# 动态设置标题
allure.dynamic.title(f"测试 {user_type} 用户权限")
# 动态设置描述
allure.dynamic.description(f"""
测试 {user_type} 用户的权限:
1. 检查登录权限
2. 检查操作权限
3. 检查数据访问权限
""")
with allure.step(f"检查 {user_type} 用户权限"):
if user_type == "admin":
permissions = ["read", "write", "delete"]
elif user_type == "user":
permissions = ["read", "write"]
else:
permissions = ["read"]
allure.attach(
f"用户类型: {user_type}n权限列表: {permissions}",
name="权限信息",
attachment_type=allure.attachment_type.TEXT
)
assert len(permissions) > 0
7.3 参数化与 fixture 结合
示例:
import pytest
import allure
@pytest.fixture
def user_data(request):
"""用户数据 fixture"""
user_type = request.param
return {
"admin": {"username": "admin", "role": "administrator"},
"user": {"username": "user", "role": "normal"},
"guest": {"username": "guest", "role": "visitor"}
}[user_type]
@allure.feature("用户管理")
@pytest.mark.parametrize("user_data", ["admin", "user", "guest"], indirect=True)
@allure.title("测试 {user_data[username]} 用户功能")
def test_user_functionality(user_data):
"""测试不同用户的功能"""
with allure.step(f"验证 {user_data['username']} 用户"):
allure.attach(
f"用户名: {user_data['username']}n角色: {user_data['role']}",
name="用户信息",
attachment_type=allure.attachment_type.TEXT
)
assert user_data["username"] is not None
assert user_data["role"] is not None
8. pytest mark 与 Allure 集成
8.1 自定义 mark 与 Allure 标签
在 pytest.ini 中定义 mark:
[pytest]
markers =
smoke: 冒烟测试
regression: 回归测试
slow: 慢速测试
api: API 测试
ui: UI 测试
在测试中使用 mark:
import pytest
import allure
@allure.feature("用户管理")
@pytest.mark.smoke
@allure.tag("冒烟测试")
def test_login_smoke():
"""冒烟测试:登录功能"""
assert True
@allure.feature("用户管理")
@pytest.mark.regression
@allure.tag("回归测试")
def test_login_regression():
"""回归测试:登录功能"""
assert True
@allure.feature("订单管理")
@pytest.mark.slow
@allure.tag("慢速测试")
def test_order_slow():
"""慢速测试:订单功能"""
assert True
按 mark 运行测试:
# 只运行冒烟测试
pytest -m smoke --alluredir=./allure-results
# 运行回归测试
pytest -m regression --alluredir=./allure-results
# 排除慢速测试
pytest -m "not slow" --alluredir=./allure-results
8.2 skip 和 xfail 与 Allure
skip 示例:
import pytest
import allure
@allure.feature("用户管理")
@pytest.mark.skip(reason="功能尚未实现")
def test_unimplemented_feature():
"""跳过的测试"""
assert False
@allure.feature("用户管理")
@pytest.mark.skipif(True, reason="条件不满足")
def test_conditional_skip():
"""条件跳过的测试"""
assert True
xfail 示例:
import pytest
import allure
@allure.feature("用户管理")
@pytest.mark.xfail(reason="已知问题,待修复")
def test_known_issue():
"""预期失败的测试"""
assert False # 这个失败是预期的
9. 附件功能集成
9.1 添加截图
Selenium 截图示例:
import allure
import pytest
from selenium import webdriver
@pytest.fixture(scope="function")
def driver():
"""WebDriver fixture"""
driver = webdriver.Chrome()
yield driver
driver.quit()
def test_login_with_screenshot(driver):
"""登录测试带截图"""
driver.get("https://example.com/login")
# 登录前截图
screenshot = driver.get_screenshot_as_png()
allure.attach(
screenshot,
name="登录页面",
attachment_type=allure.attachment_type.PNG
)
# 执行登录操作
driver.find_element_by_id("username").send_keys("admin")
driver.find_element_by_id("password").send_keys("123456")
driver.find_element_by_id("login-btn").click()
# 登录后截图
screenshot_after = driver.get_screenshot_as_png()
allure.attach(
screenshot_after,
name="登录后页面",
attachment_type=allure.attachment_type.PNG
)
assert "dashboard" in driver.current_url
9.2 添加文本和 JSON 附件
示例:
import allure
import json
def test_with_attachments():
"""测试带多种附件"""
# 添加普通文本
allure.attach(
"这是测试日志信息n包含多行内容",
name="测试日志",
attachment_type=allure.attachment_type.TEXT
)
# 添加 JSON 数据
data = {
"username": "admin",
"status": "active",
"permissions": ["read", "write", "delete"]
}
allure.attach(
json.dumps(data, indent=2, ensure_ascii=False),
name="用户数据",
attachment_type=allure.attachment_type.JSON
)
# 添加 HTML
html_content = """
<html>
<head><title>测试页面</title></head>
<body>
<h1>这是测试 HTML 内容</h1>
<table border="1">
<tr><th>用户名</th><th>状态</th></tr>
<tr><td>admin</td><td>active</td></tr>
</table>
</body>
</html>
"""
allure.attach(
html_content,
name="测试页面",
attachment_type=allure.attachment_type.HTML
)
assert True
9.3 在 fixture 中自动添加附件
示例:
import pytest
import allure
@pytest.fixture(autouse=True)
def auto_attach_environment():
"""自动附加环境信息"""
import platform
import sys
env_info = f"""
操作系统: {platform.system()}
系统版本: {platform.version()}
Python 版本: {sys.version}
"""
allure.attach(
env_info,
name="环境信息",
attachment_type=allure.attachment_type.TEXT
)
yield
def test_with_auto_attach():
"""测试会自动附加环境信息"""
assert True
10. 环境信息配置
10.1 创建环境配置文件
创建 environment.properties 文件:
# 操作系统信息
OS=Windows 10
OS.Version=10.0.19045
# Python 信息
Python.Version=3.9.0
Pytest.Version=7.0.0
# 浏览器信息
Browser=Chrome
Browser.Version=91.0
# 测试环境
Environment=Test
Base.URL=https://test.example.com
# 数据库信息
Database=MySQL
Database.Version=8.0
10.2 使用环境配置文件
方法 1:手动复制:
# 运行测试
pytest test_example.py --alluredir=./allure-results
# 手动复制 environment.properties 到 allure-results 目录
copy environment.properties allure-results/
# 生成报告
allure generate ./allure-results -o ./allure-report --clean
方法 2:使用 pytest fixture 自动生成:
import pytest
import allure
import platform
import sys
import os
@pytest.fixture(scope="session", autouse=True)
def configure_allure_environment():
"""配置 Allure 环境信息"""
environment = {
"OS": platform.system(),
"OS Version": platform.version(),
"Python Version": sys.version.split()[0],
"Pytest Version": pytest.__version__,
}
# 写入环境信息到 allure-results 目录
allure_dir = "./allure-results"
os.makedirs(allure_dir, exist_ok=True)
env_file = os.path.join(allure_dir, "environment.properties")
with open(env_file, "w", encoding="utf-8") as f:
for key, value in environment.items():
f.write(f"{key}={value}n")
yield
10.3 动态添加环境信息
示例:
import allure
import platform
import sys
def test_with_environment_info():
"""测试带环境信息"""
# 动态添加环境信息
allure.dynamic.environment(
OS=platform.system(),
Python=sys.version.split()[0],
Pytest=pytest.__version__
)
assert True
11. 历史记录功能
11.1 启用历史记录
方法 1:保留历史目录:
# 第一次运行
pytest test_example.py --alluredir=./allure-results
allure generate ./allure-results -o ./allure-report --clean
# 第二次运行(历史记录会自动保存)
pytest test_example.py --alluredir=./allure-results
allure generate ./allure-results -o ./allure-report
# 注意:不要使用 --clean,这样会保留历史记录
方法 2:手动复制历史目录:
# 第一次运行
pytest test_example.py --alluredir=./allure-results
allure generate ./allure-results -o ./allure-report --clean
# 第二次运行前,复制历史目录
# Windows
xcopy /E /I allure-reporthistory allure-resultshistory
# Linux/Mac
cp -r allure-report/history allure-results/history
# 然后生成报告
pytest test_example.py --alluredir=./allure-results
allure generate ./allure-results -o ./allure-report
11.2 查看历史趋势
在 Allure 报告的”Graphs”页面,可以查看:
- 测试用例数量的趋势
- 通过率趋势
- 失败率趋势
- 执行时间趋势
12. 完整实战示例
12.1 示例 1:用户登录测试完整集成
项目结构:
login_test_project/
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ └── test_login.py
├── pytest.ini
├── requirements.txt
└── README.md
conftest.py:
import pytest
import allure
import platform
import sys
import os
@pytest.fixture(scope="session", autouse=True)
def configure_allure_environment():
"""配置 Allure 环境信息"""
environment = {
"OS": platform.system(),
"OS Version": platform.version(),
"Python Version": sys.version.split()[0],
"Pytest Version": pytest.__version__,
}
allure_dir = "./allure-results"
os.makedirs(allure_dir, exist_ok=True)
env_file = os.path.join(allure_dir, "environment.properties")
with open(env_file, "w", encoding="utf-8") as f:
for key, value in environment.items():
f.write(f"{key}={value}n")
yield
@pytest.fixture(scope="function")
def login_data():
"""登录数据 fixture"""
return {
"admin": {"username": "admin", "password": "admin123"},
"user": {"username": "user", "password": "user123"},
}
test_login.py:
import pytest
import allure
@allure.feature("用户管理")
@allure.story("用户登录")
class TestLogin:
"""用户登录测试类"""
@allure.title("测试管理员登录")
@allure.severity(allure.severity_level.BLOCKER)
@allure.description("""
测试管理员登录功能:
1. 打开登录页面
2. 输入管理员账号和密码
3. 点击登录按钮
4. 验证登录成功
""")
def test_admin_login(self, login_data):
"""测试管理员登录"""
admin_data = login_data["admin"]
with allure.step("打开登录页面"):
print("打开登录页面")
allure.attach(
"登录页面已打开",
name="页面状态",
attachment_type=allure.attachment_type.TEXT
)
with allure.step("输入管理员账号和密码"):
username = admin_data["username"]
password = admin_data["password"]
print(f"输入用户名: {username}")
print(f"输入密码: {password}")
allure.attach(
f"用户名: {username}n密码: {password}",
name="登录信息",
attachment_type=allure.attachment_type.TEXT
)
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录成功"):
# 模拟登录验证
login_success = True
allure.attach(
f"登录结果: {'成功' if login_success else '失败'}",
name="登录结果",
attachment_type=allure.attachment_type.TEXT
)
assert login_success
@allure.title("测试普通用户登录")
@allure.severity(allure.severity_level.NORMAL)
def test_user_login(self, login_data):
"""测试普通用户登录"""
user_data = login_data["user"]
with allure.step("打开登录页面"):
print("打开登录页面")
with allure.step("输入普通用户账号和密码"):
username = user_data["username"]
password = user_data["password"]
print(f"输入用户名: {username}")
print(f"输入密码: {password}")
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录成功"):
login_success = True
assert login_success
@allure.title("测试登录失败(错误密码)")
@allure.severity(allure.severity_level.NORMAL)
def test_login_failed(self, login_data):
"""测试登录失败"""
with allure.step("打开登录页面"):
print("打开登录页面")
with allure.step("输入错误的密码"):
username = login_data["admin"]["username"]
password = "wrong_password"
print(f"输入用户名: {username}")
print(f"输入错误密码: {password}")
with allure.step("点击登录按钮"):
print("点击登录按钮")
with allure.step("验证登录失败提示"):
error_msg = "密码错误"
allure.attach(
f"错误信息: {error_msg}",
name="错误信息",
attachment_type=allure.attachment_type.TEXT
)
assert "密码错误" in error_msg
pytest.ini:
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
--alluredir=./allure-results
-v
--tb=short
markers =
smoke: 冒烟测试
regression: 回归测试
requirements.txt:
pytest>=7.0.0
allure-pytest>=2.13.0
运行测试:
# 安装依赖
pip install -r requirements.txt
# 运行测试
pytest
# 生成并查看报告
allure serve ./allure-results
12.2 示例 2:API 测试完整集成
test_api.py:
import allure
import pytest
import requests
import json
@allure.feature("API 测试")
class TestAPI:
"""API 测试类"""
BASE_URL = "https://api.example.com"
@allure.story("用户 API")
@allure.title("测试获取用户信息")
@allure.severity(allure.severity_level.CRITICAL)
def test_get_user_info(self):
"""测试获取用户信息"""
user_id = 1
with allure.step(f"发送 GET 请求获取用户 {user_id} 的信息"):
url = f"{self.BASE_URL}/users/{user_id}"
response = requests.get(url)
allure.attach(
f"请求 URL: {url}n请求方法: GET",
name="请求信息",
attachment_type=allure.attachment_type.TEXT
)
with allure.step("验证响应状态码"):
assert response.status_code == 200
allure.attach(
f"状态码: {response.status_code}",
name="响应状态码",
attachment_type=allure.attachment_type.TEXT
)
with allure.step("验证响应数据"):
data = response.json()
allure.attach(
json.dumps(data, indent=2, ensure_ascii=False),
name="响应数据",
attachment_type=allure.attachment_type.JSON
)
assert data["id"] == user_id
assert "name" in data
@allure.story("用户 API")
@allure.title("测试创建用户")
@allure.severity(allure.severity_level.CRITICAL)
def test_create_user(self):
"""测试创建用户"""
new_user = {
"name": "测试用户",
"email": "test@example.com",
"age": 25
}
with allure.step("发送 POST 请求创建用户"):
url = f"{self.BASE_URL}/users"
response = requests.post(url, json=new_user)
allure.attach(
json.dumps(new_user, indent=2, ensure_ascii=False),
name="请求数据",
attachment_type=allure.attachment_type.JSON
)
with allure.step("验证创建成功"):
assert response.status_code == 201
data = response.json()
allure.attach(
json.dumps(data, indent=2, ensure_ascii=False),
name="响应数据",
attachment_type=allure.attachment_type.JSON
)
assert data["name"] == new_user["name"]
assert "id" in data
13. CI/CD 集成
13.1 GitHub Actions 集成
创建 .github/workflows/test.yml:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Install Allure
run: |
wget https://github.com/allure-framework/allure2/releases/download/2.13.2/allure-2.13.2.tgz
tar -zxvf allure-2.13.2.tgz
sudo mv allure-2.13.2 /opt/allure
sudo ln -s /opt/allure/bin/allure /usr/local/bin/allure
- name: Run tests
run: |
pytest --alluredir=./allure-results
- name: Generate report
run: |
allure generate ./allure-results -o ./allure-report --clean
- name: Upload report
uses: actions/upload-artifact@v2
with:
name: allure-report
path: allure-report
13.2 Jenkins 集成
Jenkinsfile:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install Dependencies') {
steps {
sh 'pip install -r requirements.txt'
}
}
stage('Run Tests') {
steps {
sh 'pytest --alluredir=./allure-results'
}
}
stage('Generate Report') {
steps {
sh 'allure generate ./allure-results -o ./allure-report --clean'
}
}
}
post {
always {
allure([
includeProperties: false,
jdk: '',
properties: [],
reportBuildPolicy: 'ALWAYS',
results: [[path: 'allure-results']]
])
}
}
}
13.3 GitLab CI 集成
创建 .gitlab-ci.yml:
stages:
- test
test:
stage: test
image: python:3.9
before_script:
- pip install -r requirements.txt
- apt-get update && apt-get install -y wget unzip
- wget https://github.com/allure-framework/allure2/releases/download/2.13.2/allure-2.13.2.tgz
- tar -zxvf allure-2.13.2.tgz
- export PATH=$PATH:$(pwd)/allure-2.13.2/bin
script:
- pytest --alluredir=./allure-results
- allure generate ./allure-results -o ./allure-report --clean
artifacts:
paths:
- allure-report
expire_in: 30 days
14. 常见问题和解决方案
14.1 问题 1:allure 命令找不到
问题描述:
allure --version
# 错误: 'allure' 不是内部或外部命令,也不是可运行的程序
解决方案:
- 检查 Allure 是否已安装
- 检查环境变量 PATH 是否包含 Allure 的 bin 目录
- 重新安装 Allure 并配置环境变量
Windows 解决方案:
# 检查环境变量
$env:PATH -split ';' | Select-String "allure"
# 如果找不到,手动添加到 PATH
# 或者使用完整路径
C:allurebinallure.exe --version
14.2 问题 2:allure-results 目录为空
问题描述:运行 pytest 后,allure-results 目录为空或没有生成文件。
解决方案:
- 检查是否安装了 allure-pytest
- 检查 pytest 命令中是否包含
--alluredir参数 - 检查 pytest.ini 中是否配置了
addopts
验证步骤:
# 1. 检查插件是否安装
pip show allure-pytest
# 2. 检查 pytest 插件列表
pytest --trace-config | grep allure
# 3. 手动指定参数运行
pytest test_example.py --alluredir=./allure-results -v
14.3 问题 3:报告中文乱码
问题描述:Allure 报告中中文显示为乱码。
解决方案:
- 确保文件使用 UTF-8 编码
- 在 pytest.ini 中配置编码
- 在生成报告时指定编码
pytest.ini 配置:
[pytest]
addopts =
--alluredir=./allure-results
--tb=short
生成报告时:
# 确保使用 UTF-8 编码
allure generate ./allure-results -o ./allure-report --clean
14.4 问题 4:历史记录不显示
问题描述:生成的报告中没有历史趋势图。
解决方案:
- 确保 allure-report/history 目录存在
- 在生成新报告前,复制历史目录到 allure-results
- 生成报告时不要使用 –clean(或先复制历史)
脚本示例:
# Windows
if exist allure-reporthistory (
xcopy /E /I allure-reporthistory allure-resultshistory
)
pytest --alluredir=./allure-results
allure generate ./allure-results -o ./allure-report
# Linux/Mac
if [ -d "allure-report/history" ]; then
cp -r allure-report/history allure-results/history
fi
pytest --alluredir=./allure-results
allure generate ./allure-results -o ./allure-report
14.5 问题 5:附件无法显示
问题描述:报告中附加的截图或文件无法显示。
解决方案:
- 检查附件数据是否正确
- 检查附件类型是否正确
- 检查文件路径是否正确
示例:
import allure
# 确保附件数据是字节类型
screenshot = driver.get_screenshot_as_png() # 返回 bytes
allure.attach(
screenshot, # 必须是 bytes
name="截图",
attachment_type=allure.attachment_type.PNG
)
15. 最佳实践
15.1 项目结构建议
推荐的目录结构:
project/
├── tests/
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_login.py
│ ├── test_user.py
│ └── test_order.py
├── allure-results/ # Allure 结果数据(自动生成,可加入 .gitignore)
├── allure-report/ # Allure 报告(自动生成,可加入 .gitignore)
├── pytest.ini # pytest 配置文件
├── requirements.txt # 依赖文件
└── README.md # 项目说明
.gitignore 配置:
# Allure
allure-results/
allure-report/
*.log
15.2 测试代码规范
1. 使用描述性的标题和描述:
@allure.title("测试管理员登录功能")
@allure.description("""
测试管理员登录功能:
1. 输入正确的管理员账号和密码
2. 验证登录成功
3. 检查用户权限
""")
def test_admin_login():
pass
2. 合理使用步骤:
def test_login():
with allure.step("打开登录页面"):
# 操作
with allure.step("输入用户名和密码"):
# 操作
with allure.step("点击登录按钮"):
# 操作
with allure.step("验证登录成功"):
# 断言