目录

pytest-pure-report

美观、实用的 pytest HTML 报告插件,提供清晰的测试统计和丰富的交互功能。

功能特性

统计与可视化

  • 完整的测试状态统计:通过、失败、错误、跳过、预期失败、意外通过、未执行
  • 饼图直观展示通过率,堆叠条形图展示各测试类的用例分布
  • 智能统计公式:总用例数、已收集、有效用例数、通过率

自定义与设计

  • 自定义 Logo(支持本地图片或远程 URL)
  • 自定义报告标题和测试环境标识
  • 现代化浅色主题,清晰可读的布局
  • 全屏自适应布局,适配不同尺寸屏幕(小屏自动转为上下布局)

测试结果(左右结构)

  • 参考 Allure 报告的左右结构布局:左侧为测试用例树,右侧为用例详情
  • 点击左侧测试用例后,右侧展示该用例的完整详情
  • 支持 Allure 装饰器(feature/story/title),自动构建层级路径
  • 按功能模块 > 用户故事分组展示,支持展开/折叠
  • 搜索过滤:按名称搜索,按状态筛选
  • 合并显示位置字段:文件路径>类名>方法名

执行过程(Execution)

  • 每个测试用例的执行过程按阶段分组展示:
    • 前置处理(Set up):fixture 中 yield 之前的步骤
    • 测试步骤(Test Body):测试用例主体执行过程
    • 后置处理(Tear down):fixture 中 yield 之后的步骤
  • fixture 无嵌套内容时不显示展开箭头,有内容时可点击展开
  • pure.step 步骤可点击展开,显示该步骤执行期间捕获的日志和附件

媒体支持

  • 支持测试截图,支持缩略图预览和大图查看(可配置 always/fail_only/never)
  • 支持测试录屏,支持在线播放(可配置 always/fail_only/never)
  • 支持 Playwright Trace 录制与可视化回放(可配置 always/fail_only/never)
    • 按用例独立录制,每个用例生成一个 trace zip 文件
    • 报告中每个用例卡片下显示「🎬 Trace 记录」区段(无 trace 时自动隐藏)
    • 点击「查看 Trace」按钮在新标签页打开 Playwright Trace Viewer,可前后穿梭于测试每个操作,直观查看页面快照、DOM、网络请求、控制台日志等
    • 自动复制 Playwright 自带 Trace Viewer SPA 资源到报告目录,支持离线查看

交互功能

  • 返回顶部按钮,方便快速导航
  • 失败用例显示完整错误堆栈和执行原因

pure 公共 API(推荐使用)

  • 完全参考 allure 的 API 设计,提供装饰器、上下文管理器和动态函数
  • 操作步骤:通过 pure.step 记录步骤(自动捕获异常状态、自动识别阶段、自动捕获步骤级日志和附件)
  • 断言结果:在原生 assert 后调用 pure.record* 即可在报告中展示
  • 附件:通过 pure.attach 添加文本/JSON/图片等附件(自动关联到当前步骤)
  • 标签:通过 pure.feature / pure.story / pure.severity 等装饰器添加标签(用于层级分组,不在详情中单独展示)
  • 用法简单、零侵入,不调用也不会影响测试执行

安装

# 从本地安装(开发模式)
cd pytest-pure-report
pip install -e .

# 或者从 PyPI 安装(如果已发布)
pip install pytest-pure-report

快速开始

基本使用

安装插件后,运行 pytest 时会自动生成报告:

pytest test_cases/

指定报告目录

pytest test_cases/ --report-dir=outputs/reports

指定测试环境

pytest test_cases/ --env=test

支持本地图片路径或远程 URL:

# 使用本地图片
pytest test_cases/ --logo=assets/logo.png

# 使用远程 URL
pytest test_cases/ --logo=https://example.com/logo.png

自定义标题

pytest test_cases/ --title="API 自动化测试报告"

完整示例

pytest test_cases/ \
    --report-dir=outputs/reports \
    --report-filename=test_report.html \
    --env=prod \
    --logo=assets/logo.png \
    --title="自动化测试报告" \
    -v

配置选项

命令行选项

选项 说明 默认值
--report-dir 报告输出目录 pure_report
--report-filename 报告文件名 自动生成时间戳文件名
--env 测试环境标识 test
--logo 自定义 Logo 路径(支持本地文件或 http/https URL) 无
--title 自定义报告标题 自动化测试报告

pytest.ini 配置

在项目根目录创建 pytest.ini 文件:

[pytest]
report_dir = outputs/reports
report_filename = test_report.html
env = test
logo = assets/logo.png
title = 自动化测试报告
screenshot_scope = fail_only
video_scope = never
trace_scope = never

环境变量配置

# 设置测试环境
export TEST_ENV=prod

# ========== 浏览器信息(仅 UI 测试需要设置,接口测试无需设置) ==========
# 注意:浏览器信息为按需显示,只有设置了 BROWSER_TYPE 才会在报告中渲染浏览器行。
# 未设置 BROWSER_TYPE 时(如接口测试),报告将不显示浏览器、模式、分辨率等信息。

# 设置浏览器类型(chromium, firefox, webkit)—— 设置后报告才显示浏览器信息
export BROWSER_TYPE=chromium

# 设置无头模式(true 或 false)—— 未设置时默认为 false(有头模式)
export HEADLESS=true

# 设置浏览器窗口分辨率 —— 未设置时报告不显示分辨率
export BROWSER_WIDTH=1920
export BROWSER_HEIGHT=1080

# ========== 媒体捕获配置 ==========
# 设置截图捕获策略(always/fail_only/never)
export SCREENSHOT_SCOPE=fail_only

# 设置录屏捕获策略(always/fail_only/never)
export VIDEO_SCOPE=never

# 设置 Trace 录制策略(always/fail_only/never)
export TRACE_SCOPE=never

# 设置截图和录屏文件路径
export SCREENSHOT_PATH=/path/to/screenshots
export VIDEO_PATH=/path/to/videos

# 设置 trace 文件路径
export TRACE_PATH=/path/to/traces

# 运行测试
pytest test_cases/

配置优先级

配置项按以下优先级生效(高优先级覆盖低优先级):

命令行参数 > 环境变量 > pytest.ini 配置 > 默认值

截图、录屏和 Trace 配置

配置项 说明 默认值
SCREENSHOT_SCOPE 截图捕获策略 fail_only
VIDEO_SCOPE 录屏捕获策略 never
TRACE_SCOPE Trace 录制策略 never
SCREENSHOT_PATH 截图文件目录 outputs/screenshots
VIDEO_PATH 录屏文件目录 outputs/videos
TRACE_PATH Trace 文件目录 outputs/traces

截图/录屏/Trace 策略说明:

  • always:所有用例都捕获/录制
  • fail_only:仅失败用例捕获/保留(默认截图策略;trace 录制后通过用例会自动删除)
  • never:不捕获/录制

Trace 录制说明

Trace 是 Playwright 提供的测试过程可视化能力,开启后会录制测试执行全过程,打包为 .zip 文件,包含:

录制内容 说明
Snapshots(页面快照) 每个操作后的 DOM 状态,可前后穿梭查看页面在任意时刻的样子
Screenshots(截图) 每个操作自动截图
Network(网络) 所有 HTTP 请求/响应详情(含 headers、body)
Console logs 浏览器控制台输出
Source(源码) 每个操作对应的代码位置(可点击跳转)
Action log(动作日志) 所有 Playwright 操作的时间线(含选择器、耗时、错误)

按用例录制:每个用例独立录制一个 trace zip 文件,文件按用例名分子目录存储:

traces/
├── test_login_success/
│   └── test_login_success_1790662054676.zip
├── test_enter_via_avatar_click/
│   └── test_enter_via_avatar_click_1790662059536.zip

报告集成:报告中每个用例卡片下会显示「🎬 Trace 记录」区段(绿色背景),点击「查看 Trace」按钮在新标签页打开 Playwright Trace Viewer 进行可视化回放。

Trace Viewer 部署:报告生成时会自动复制 Playwright 自带的 Trace Viewer SPA 资源到报告目录的 trace-viewer/ 子目录,无需额外安装。由于 Trace Viewer 依赖 Service Worker,必须通过 HTTP 服务器访问报告(直接用 file:// 协议打开会显示友好提示):

# 进入报告目录启动 HTTP 服务器
cd outputs/pure_reports/<timestamp>
python -m http.server 8000

# 浏览器访问报告,点击用例卡片下的「查看 Trace」按钮
# http://localhost:8000/test_report_<timestamp>.html

报告结构

整体布局

报告采用全屏自适应布局,主要区域包括:

  • 报告头部:Logo、标题、环境标识
  • 测试结果概览:统计卡片、饼图、堆叠条形图
  • 测试结果区域(左右结构,参考 Allure):
    • 左侧面板:测试用例树(按 feature > story 分组),支持搜索和状态筛选
    • 右侧面板:选中用例的详情面板

用例详情面板

点击左侧测试用例后,右侧展示:

  • 位置:文件路径>类名>方法名
  • 优先级:从 pure.severity 标签提取
  • 结果:passed/failed/error/skipped 等
  • 耗时:用例执行总耗时
  • 参数(Parameters):参数化用例的参数列表(可折叠)
  • 执行过程(Execution):按阶段分组展示
    • 前置处理(Set up):fixture 列表(可展开查看嵌套步骤)
    • 测试步骤(Test Body):pure.step 步骤列表(可展开查看步骤日志/附件)
    • 后置处理(Tear down):fixture 列表(可展开查看嵌套步骤)
  • 断言结果:表格展示断言详情
  • 截图/录屏:按配置展示
  • Trace 记录:按配置展示(开启 trace 时,每个用例独立录制,无 trace 时自动隐藏)
  • 错误信息:失败用例的错误堆栈

测试状态说明

状态含义

  • passed: 正常通过:断言全部成功,无异常,运行完整
  • failed: 断言失败:用例执行完毕,但断言不成立或主动调用 pytest.fail()
  • error: 执行异常:测试未完整运行(setup/teardown/导入/运行时抛出未捕获异常)
  • xfail: 预期失败:标记了 @pytest.mark.xfail,且实际结果确实是失败
  • xpassed: 意外通过:标记了 @pytest.mark.xfail,但实际运行成功了
  • skipped: 主动跳过:通过 @skip/skipif/xfail(condition=True) 跳过,未执行测试体
  • deselected: 收集阶段剔除:被 -k、–ignore、–collect-only 或配置文件过滤,未进入执行流程

统计公式

  • 总用例数(Total) = passed + failed + error + xfail + xpassed + skipped + deselected
  • 已收集用例数(Selected) = passed + failed + error + xfail + xpassed + skipped
  • 有效用例数(Executed) = passed + failed + error
  • 通过率(Pass Rate) = passed / (passed + failed + error) × 100%

示例测试用例

参数化测试用例

import pytest

class TestLogin:
    @pytest.fixture(params=[
        {"name": "登录页面URL正确", "url": "/login"},
        {"name": "用户名输入框存在", "selector": "#username"},
        {"name": "密码输入框存在", "selector": "#password"},
    ])
    def test_case(self, request):
        return request.param

    def test_login_page_load(self, test_case):
        """测试登录页面加载"""
        print(f"测试用例: {test_case['name']}")
        assert True

普通测试用例

import pytest

class TestExample:
    def test_passed(self):
        """测试通过的用例"""
        assert True

    def test_failed(self):
        """测试失败的用例"""
        assert False, "故意失败"

    @pytest.mark.skip(reason="跳过原因")
    def test_skipped(self):
        """测试跳过的用例"""
        assert True

    @pytest.mark.xfail(reason="已知问题")
    def test_xfail(self):
        """预期失败的用例"""
        assert False

    def test_with_logs(self):
        """带有日志输出的用例"""
        print("这是一条输出日志")
        assert True

截图和录屏

在 conftest.py 中配置 page fixture,测试失败时自动捕获截图和录屏:

import os
import time
import pytest

@pytest.fixture(scope="function")
def page():
    """浏览器页面 fixture"""
    from playwright.sync_api import sync_playwright
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        yield page
        browser.close()

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    """测试失败时自动截图"""
    outcome = yield
    report = outcome.get_result()

    if report.when == "call" and report.failed:
        page = item.funcargs.get("page")
        if page:
            screenshot_dir = os.path.join(os.getcwd(), "outputs", "screenshots")
            os.makedirs(screenshot_dir, exist_ok=True)
            screenshot_path = os.path.join(screenshot_dir, f"{item.name}_{int(time.time()*1000)}.png")
            page.screenshot(path=screenshot_path)

使用注意事项

  1. 不使用 -s 参数:为了让报告能够捕获测试中的 print 和 log 输出,请不要使用 -s(禁用输出捕获)参数
  2. 日志配置:确保 pytest 的日志捕获功能正常工作(使用 --log-cli-level 设置日志级别)
  3. 编码问题:报告文件使用 UTF-8 编码,确保测试代码中的中文输出也是 UTF-8 编码
  4. 参数化名称:参数化用例中如果包含 name 字段,将自动作为用例名称显示
  5. 浏览器信息(按需显示):浏览器信息仅在显式设置 BROWSER_TYPE(环境变量或命令行参数)时才在报告中显示。接口测试等不涉及浏览器的场景无需设置,报告将自动隐藏浏览器、模式、分辨率等信息。命令行参数优先级高于环境变量
  6. 执行过程:测试用例的执行过程按「前置处理 / 测试步骤 / 后置处理」三个阶段分组展示。fixture 无嵌套内容时不显示展开箭头;pure.step 步骤可点击展开查看该步骤执行期间捕获的日志和附件
  7. 截图文件名:截图文件名需遵循 <test_name>_<timestamp>.png 格式,报告插件会自动匹配并显示
  8. 录屏文件名:录屏文件名需遵循 <test_name>_<timestamp>.webm 格式,报告插件会自动匹配并显示
  9. Trace 录制:Trace 仅在使用 Playwright 浏览器测试时可用。开启 TRACE_SCOPE 后,每个用例独立录制一个 trace zip 文件,按用例名分子目录存储在 TRACE_PATH 目录下。报告生成时会自动复制 Playwright 自带 Trace Viewer SPA 到 report_dir/trace-viewer/ 子目录,点击用例卡片下的「查看 Trace」按钮可在新标签页打开 Trace Viewer 进行可视化回放。由于 Trace Viewer 依赖 Service Worker,必须通过 HTTP 服务器访问报告(如 python -m http.server 8000),直接用 file:// 协议打开会显示友好提示

pure 公共 API 使用指南

pure 是本插件提供的一套完全参考 allure 的公共 API,用于在报告中展示 操作步骤、断言结果 和 附件。 所有 API 均为可选调用,不写也不影响测试执行。

导入方式

from pytest_pure_report import pure

API 一览

API 作用
pure.step(title) 步骤(装饰器 + 上下文管理器,自动捕获状态、日志和附件)
pure.fixture(name) fixture 装饰器(自动追踪 setup/teardown)
pure.attach(body, ...) 添加附件(文本/JSON/图片等,自动关联到当前步骤)
pure.attach.file(source, ...) 添加文件附件(自动关联到当前步骤)
pure.record(...) 记录一条断言结果(通用 API,pure 扩展)
pure.record_equal(...) 便捷方法:相等断言
pure.record_contains(...) 便捷方法:包含断言
pure.record_visible(...) 便捷方法:元素可见性断言
pure.title(title) 装饰器:用例标题
pure.feature(*names) 装饰器:feature 标签(用于层级分组)
pure.story(*names) 装饰器:story 标签(用于层级分组)
pure.severity(level) 装饰器:优先级
pure.tag(*tags) 装饰器:标签
pure.link(url, name) 装饰器:链接
pure.dynamic 运行时动态信息
pure.severity_level 优先级常量枚举
pure.attachment_type 附件类型常量枚举

1. step(装饰器 + 上下文管理器)

与 allure.step 完全一致,支持两种写法:

from pytest_pure_report import pure

# 上下文管理器
with pure.step("打开登录页面"):
    page.goto("/login")

# 装饰器(自动用函数名作 step 标题,自动提取参数)
@pure.step("输入用户名和密码")
def fill_credentials(page, username, password):
    page.fill("#username", username)
    page.fill("#password", password)

# 装饰器也可以不传参数,使用函数名作标题
@pure.step
def open_login_page(page):
    page.goto("/login")

step 内部自动捕获异常状态:

  • 无异常 → passed
  • AssertionError → failed
  • 其他异常 → broken(并重新抛出)

step 自动识别阶段(setup / call / teardown),无需手动指定:

  • fixture 中 yield 之前 → setup
  • test 函数中 → call
  • fixture 中 yield 之后 → teardown

step 自动捕获步骤级日志和附件:

  • 步骤执行期间通过 loguru 输出的日志自动捕获到 step_data['log']
  • 步骤执行期间通过 pure.attach 添加的附件自动关联到 step_data['attachments']
  • 报告中步骤行可点击展开,显示该步骤的日志和附件
  • 支持嵌套步骤(父步骤的子步骤独立记录)

2. fixture(自动追踪)

与 allure.fixture 一致,装饰 fixture 函数,插件通过 pytest hook 自动追踪阶段:

import pytest
from pytest_pure_report import pure

@pytest.fixture
@pure.fixture("登录")
def login(page):
    with pure.step("打开登录页面"):
        page.goto("/login")
    yield page
    with pure.step("关闭浏览器"):
        page.context.close()

# 也可不传参数
@pytest.fixture
@pure.fixture
def page():
    ...

3. 断言记录(pure 扩展)

与原生 assert 配合,在报告中展示断言对比:

# 通用 API
assert actual == expected
pure.record("描述", actual, expected, type="==")

# 便捷方法(自动判断 passed)
pure.record_equal(page.title(), "GitLink", "验证页面标题")
pure.record_contains(resp.text, "success", "验证响应包含 success")
pure.record_visible(is_visible, "验证元素可见")

4. 附件

与 allure.attach 一致,附件自动关联到当前步骤(如果在 pure.step 上下文内调用):

# 文本附件
pure.attach("hello world", name="问候", attachment_type=pure.attachment_type.TEXT)

# JSON 附件
pure.attach('{"key": "value"}', name="数据", attachment_type=pure.attachment_type.JSON)

# 文件附件
pure.attach.file("path/to/screenshot.png", name="截图")

5. 标签装饰器

与 allure 完全一致,用于测试用例树的层级分组:

@pure.feature("登录")
@pure.story("成功登录")
@pure.severity(pure.severity_level.CRITICAL)
@pure.tag("smoke")
@pure.title("验证用户使用正确账号可以登录")
@pure.link("https://gitlink.org.cn/issue/1", name="issue-1")
def test_login_success(page):
    ...

6. 运行时动态信息(Dynamic)

与 allure.dynamic 一致,在运行时动态修改信息:

def test_something(page):
    pure.dynamic.title("动态标题")
    pure.dynamic.tag("dynamic-tag")
    pure.dynamic.severity(pure.severity_level.BLOCKER)

报告展示效果

  • 执行过程(Execution):按「前置处理(Set up)/ 测试步骤(Test Body)/ 后置处理(Tear down)」分组展示。
    • fixture 行:有嵌套内容时可点击展开,无内容时显示为简单行(不显示展开箭头)
    • pure.step 步骤行:有日志/附件/错误时可点击展开查看详情
    • 每行显示「状态图标、步骤标题、参数、耗时」
  • 断言结果 表格:展示「断言描述、断言类型、预期值、实际值、结果」列,并显示「全部通过 N 条」或「X/N 通过 N 条」汇总
  • 附件:步骤执行期间的附件显示在对应步骤的展开区域内;步骤外的附件显示在所属阶段区段

完整示例

import pytest
from pytest_pure_report import pure

@pure.feature("登录")
class TestLogin:

    @pytest.fixture
    @pure.fixture("登录")
    def login(self, page):
        with pure.step("打开登录页面"):
            page.goto("/login")
        yield page

    @pure.story("成功登录")
    @pure.severity(pure.severity_level.CRITICAL)
    @pure.title("验证用户使用正确账号可以登录")
    def test_login_success(self, page, login):
        with pure.step("验证用户头像可见"):
            is_visible = page.locator(".currentImg").is_visible()
            assert is_visible
            pure.record_visible(is_visible, "验证用户头像可见")

更详细的 API 说明请参考 pure.py 源码文档。

项目结构

pytest-pure-report/
├── pyproject.toml                    # 项目配置文件
├── README.md                         # 项目文档
├── LICENSE                           # 许可证
├── tests/                            # 测试文件
├── images/                           # 图标资源
├── example/                          # 示例文件
│   └── test_report_*.html            # 示例报告
└── src/
    └── pytest_pure_report/
        ├── __init__.py               # 包初始化
        ├── models.py                 # 数据模型(TestResult)
        ├── generator.py              # 报告生成器(HTML 生成)
        ├── pure.py                   # pure 公共 API(step/attach/record 等)
        └── plugin.py                 # pytest 插件(钩子和命令行选项)

开发

本地开发

# 进入项目目录
cd pytest-pure-report

# 安装开发依赖
pip install -e .

# 运行测试(在项目根目录执行)
pytest tests/ -v

# 构建包(可选)
python -m build

许可证

MIT License

贡献

欢迎提交 Issue 和 Pull Request!


pytest-pure-report - 让测试报告更美观、更实用!

关于

一个美观的 pytest HTML 报告插件,具有全面的统计功能和交互特性。

1.2 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号