目录

混合驱动自动化测试框架

兼容 Python 脚本编写YAML 数据驱动 两种模式的自动化测试框架,支持 AllurePure 两种测试报告。

核心特性

  1. 双重模式: 支持 Python 原生脚本写法(直接使用 Playwright)和 YAML 关键字写法
  2. 双报告引擎: 支持 Allure 报告和自研 Pure 报告(HTML 单文件,离线可看),通过 -r 参数切换
  3. 自动日志: 通过 loguru 记录运行日志,Pure 报告自动收集 setup/call/teardown 三阶段日志并合并展示
  4. 截图与录屏
    • 截图支持三种范围(never / fail_only / always),在测试结束后通过 hook 触发,可按结果决定
    • 录屏支持两种范围(never / always),在 context 创建时配置(Playwright 限制,无法按结果决定)
  5. 会话管理: 支持认证会话保存和复用,避免重复登录
  6. 时间戳目录: 每次运行生成独立的报告目录(含报告、截图、录屏),便于追溯历史运行
  7. 极简编写: 脚本模式下直接使用 Playwright 的 page 对象,配合 allure.steppure.step 记录步骤

框架目录结构

automation_framework/
├── config/                       # 配置目录
│   ├── __init__.py
│   └── settings.py              # 全局配置文件
├── tests/                       # 测试用例目录
│   ├── __init__.py
│   ├── conftest.py              # Pytest 配置和 Fixtures(浏览器、登录会话等)
├── testcases/                   # YAML 用例目录
├── utils/                       # 工具类目录
│   ├── __init__.py
│   ├── log_tools.py             # 日志初始化(loguru 配置)
│   ├── yaml_engine.py           # YAML 引擎
│   └── auth_session.py          # 认证会话管理
├── lib/                         # 内置第三方库
│   ├── allure-2.22.0/          # Allure 命令行工具
│   └── pytest-pure-report/     # Pure 报告插件(自研)
│       └── src/pytest_pure_report/
├── outputs/                     # 输出目录(运行后自动生成)
│   ├── logs/                    # 运行日志(每次运行一个独立日志文件)
│   ├── pure_reports/            # Pure 报告根目录
│   └── allure_reports/          # Allure 报告根目录
├── run.py                       # 测试运行入口
├── pytest.ini                   # pytest 配置
├── requirements.txt             # Python 依赖
├── Dockerfile                   # Docker 镜像配置
└── README.md                    # 项目说明

配置文件说明

config/settings.py

配置项 说明 默认值
报告配置
REPORT_TYPE 报告类型 (allure/pure) allure
REPORT_TITLE 报告标题 自动化测试报告
REPORT_ENV 测试环境标识 (test/dev/prod) test
REPORT_FILENAME 报告文件名(None 表示默认时间戳) None
PURE_REPORTS_ROOT Pure 报告根目录 outputs/pure_reports
ALLURE_REPORTS_ROOT Allure 报告根目录 outputs/allure_reports
ALLURE_BIN Allure 可执行文件路径 自动识别(优先本地安装)
截图 / 录屏
SCREENSHOT_SCOPE 截屏范围 (never/fail_only/always) fail_only
VIDEO_SCOPE 录屏范围 (never/always)。Playwright 录屏在测试前配置,无法按结果决定 never
浏览器配置
BROWSER_TYPE 浏览器类型 (chromium/firefox/webkit) chromium
HEADLESS 是否无头模式 False
BROWSER_WIDTH 浏览器窗口宽度 1920
BROWSER_HEIGHT 浏览器窗口高度 1080
BROWSER_TIMEOUT 浏览器启动超时(秒) 30
测试目标
BASE_URL 测试网站地址 http://172.20.32.203:4000
测试用户
TEST_USER_USERNAME 测试用户账号 floraachy
TEST_USER_PASSWORD 测试用户密码 12345678
TEST_USER_DISPLAY_NAME 测试用户显示名称 floraachy
其他
OUTPUTS_DIR 输出目录根路径 outputs/
LOG_PATH 日志存放路径 outputs/logs/
CASES_DIR YAML 用例目录 testcases/
AUTH_DIR 认证会话存储目录 .auth/

Allure 路径配置

框架支持两种 Allure 路径配置方式:

  1. 本地安装:设置环境变量 ALLURE_HOME 指向 Allure 安装目录
  2. 项目内置:默认使用 lib/allure-2.22.0/bin/ 下的 Allure
# 方式1: 设置环境变量(Windows)
set ALLURE_HOME=C:\allure-2.22.0

# 方式2: 使用项目内置 Allure(无需配置)
python run.py

配置数据流

截图/录屏配置的读取优先级(从高到低):

命令行参数  >  settings.py 默认值
     ↓
run.py 合并后注入环境变量
     ↓
conftest.py / plugin.py 读取环境变量

截图与录屏的差异

  • 截图:在测试结束后通过 pytest hook 触发,可以按测试结果(通过/失败)决定是否截图,支持 fail_only 模式
  • 录屏:在浏览器 context 创建时配置(Playwright 限制),测试执行前就必须决定是否开启,无法按结果决定,因此不支持 fail_only 模式

日志配置

框架使用 loguru 作为日志库,采用 “初始化模块 + 直接调用” 设计:

组件 职责
utils/log_tools.py 仅做初始化:移除默认处理器、添加控制台处理器(INFO 级别)、添加文件处理器(DEBUG 级别)
调用方(测试代码、工具类) 直接 from loguru import logger,使用 logger.info() / logger.error() / logger.debug()

初始化触发方式

在测试文件或工具模块中 import utils.log_tools(加 # noqa: F401 标注),执行模块顶层代码触发 loguru 配置。loguru 的 logger 是全局单例,初始化一次后所有模块共享配置。

from loguru import logger
import utils.log_tools  # noqa: F401 - 触发 loguru 初始化

logger.info("消息")     # 同时输出到控制台和日志文件
logger.debug("调试信息") # 仅写入日志文件(控制台 level=INFO)
logger.error("错误")    # 同时输出到控制台和日志文件

日志文件位置

  • 默认路径:outputs/logs/run_YYYYMMDD_HHMMSS.log(每次运行独立文件,不覆盖)
  • 自定义文件名:run.py 通过环境变量 RUN_LOG_FILE 注入(如 run_20260911_104557.log
  • 直接运行 pytest(不经 run.py)时,使用当前时间戳自动生成文件名

为什么不用 log_info 封装函数?

原设计在 log_tools.py 中提供 log_info(msg) / log_error(msg) 封装函数,但存在以下问题:

  1. loguru 的 logger 本身就是全局单例,封装只是增加一层跳转,无附加价值
  2. 封装只覆盖 info/errordebug/warning/exception 都用不了
  3. loguru 官方推荐用法是 from loguru import logger,直接使用更清晰

截图与录屏配置

框架对截图和录屏采用不同的触发机制,配置范围也有所不同:

截图(SCREENSHOT_SCOPE)

截图在测试结束后通过 pytest_runtest_makereport hook 触发,此时测试结果(通过/失败)已知,可以按结果决定是否截图。

范围 说明 使用场景
never 不截图 快速验证、CI 流水线
fail_only 仅测试失败时截图(默认) 日常测试,排查失败用例
always 每次测试都截图 需要完整审计追踪

录屏(VIDEO_SCOPE)

录屏在浏览器 context 创建时配置(Playwright API 限制),测试执行前就必须决定是否开启,无法提前预知测试结果。

范围 说明 使用场景
never 不录屏(默认) 快速验证、CI 流水线、节省资源
always 每次测试都录屏 复杂交互调试、需要完整回放

为何录屏不支持 fail_only Playwright 的录屏通过 record_video_dirbrowser.new_context() 时配置,必须测试前就决定是否开启。测试执行时才能知道结果,但录屏早已启动,无法回溯关闭。 如需失败证据,请使用 SCREENSHOT_SCOPE=fail_only,截图在测试后触发,可按结果决定。

配置方式

方式1:修改 settings.py 默认值

# config/settings.py
SCREENSHOT_SCOPE = "fail_only"  # never / fail_only / always
VIDEO_SCOPE = "never"           # never / always

方式2:命令行参数覆盖(优先级更高)

# 仅失败时截图,不录屏
python run.py --screenshot fail_only --video-scope never

# 全量截图录屏(调试用)
python run.py --screenshot always --video-scope always

# 不截图不录屏(最快)
python run.py --screenshot never --video-scope never

如何编写测试用例

模式一:Python 脚本模式(推荐用于复杂逻辑)

tests/ 下新建文件,直接使用 Playwright 的 page 对象。 配合 allure.steploguru 记录测试步骤和日志。

import pytest
import allure
from loguru import logger
from pytest_pure_report import pure
from config.settings import BASE_URL, TEST_USER_USERNAME, TEST_USER_PASSWORD
import utils.log_tools  # noqa: F401 - 触发 loguru 初始化(配置控制台/文件处理器)

@allure.feature("用户登录")
class TestLoginScript:

    @allure.story("登录成功")
    def test_login_success(self, page):
        """测试登录成功场景"""
        with allure.step(f"打开登录页面:{BASE_URL}/login"):
            logger.info(f"打开登录页面: {BASE_URL}/login")
            page.goto(f"{BASE_URL}/login", wait_until="networkidle")

        with allure.step("输入用户名和密码"):
            logger.info(f"输入用户名: {TEST_USER_USERNAME}")
            page.fill('input[placeholder="请输入手机号/用户名"]', TEST_USER_USERNAME)
            page.fill('input[placeholder="请输入登录密码"]', TEST_USER_PASSWORD)

        with allure.step("点击登录按钮"):
            logger.info("点击登录按钮")
            page.click("button:has-text('登 录')")

        with allure.step("验证登录成功"):
            page.wait_for_selector(".currentImg", timeout=10000)

使用认证会话管理

框架提供认证会话管理功能,可以在测试间复用登录状态:

def test_with_auth(page, auth_session):
    # 应用已保存的会话(自动登录)
    auth_session.apply_session(page.context)

    # 访问需要登录的页面
    page.goto("/dashboard")
    assert page.locator(".user-info").is_visible()

模式二:YAML 模式(推荐用于简单流程)

testcases/ 目录下新建 .yaml 文件,格式如下:

name: "测试用例名称"
steps:
  - action: "goto"          # 关键字
    desc: "步骤描述"         # 报告中显示的步骤名
    url: "https://..."       # 参数

支持的关键字详解

关键字 说明 必填参数 可选参数
goto 打开指定 URL 的页面 url -
fill 在输入框中填写文本 locator, text -
click 点击指定元素 locator -
type 模拟键盘输入(逐字符输入) locator, text delay (每个字符间隔毫秒)
hover 鼠标悬停在指定元素上 locator -
dblclick 双击指定元素 locator -
press 模拟按键操作 locator, key -
select_option 下拉框选择选项 locator, value -
assert_visible 断言元素可见 locator -
wait_for_selector 等待元素出现 locator timeout (毫秒,默认 10000)
wait_for_url 等待 URL 变化 url timeout (毫秒,默认 10000)
screenshot 页面截图 path -

使用示例

name: "用户登录测试"
steps:
  - action: "goto"
    desc: "打开登录页面"
    url: "http://172.20.32.203:4000/login"

  - action: "fill"
    desc: "输入用户名"
    locator: "input[id='login_username']"
    text: "floraachy"

  - action: "fill"
    desc: "输入密码"
    locator: "input[id='login_password']"
    text: "12345678"

  - action: "click"
    desc: "点击登录按钮"
    locator: "button:has-text('登 录')"

  - action: "wait_for_selector"
    desc: "等待头像元素出现"
    locator: ".currentImg"
    timeout: 5000

  - action: "assert_visible"
    desc: "验证登录成功"
    locator: ".currentImg"

快速开始

1. 环境准备

创建虚拟环境:

python -m venv venv
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate     # Windows

安装依赖:

pip install -r requirements.txt
playwright install

2. 运行测试

# 默认运行(按 settings.py 配置的 REPORT_TYPE 生成报告)
python run.py

# 指定 Pure 报告
python run.py -r pure

# 指定 Allure 报告 + 无头模式 + 过滤 login 关键词
python run.py -r allure --headless true -k login

命令行参数

参数 说明 示例
-r, --report-type 报告类型 (allure/pure) python run.py -r pure
-b, --browser-type 浏览器类型 (chromium/firefox/webkit) python run.py -b firefox
--headless 是否无头模式 (true/false),默认 true python run.py --headless false
-k, --keyword 按测试名称关键词过滤 python run.py -k login
--screenshot 截屏范围 (never/fail_only/always),默认 fail_only python run.py --screenshot always
--video-scope 录屏范围 (never/always),默认 never。Playwright 录屏在测试前配置,无法按结果决定 python run.py --video-scope always

使用示例:

# Pure 报告 + 无头模式 + 不截图不录屏(快速验证)
python run.py -r pure --headless true --screenshot never --video-scope never

# Allure 报告 + Firefox 浏览器 + 过滤 login 关键词
python run.py -r allure -b firefox -k login

# 全量截图录屏(调试时)
python run.py -r pure --screenshot always --video-scope always

3. Docker 运行

构建镜像:

docker build -t test-frame .

运行容器(结果挂载到本地):

docker run -v $(pwd)/outputs:/app/outputs test-frame

报告查看

Pure 报告

运行结束后,进入 outputs/pure_reports/<时间戳>/ 目录,直接用浏览器打开其中的 .html 文件即可查看报告(单文件,离线可看)。

Allure 报告

运行结束后,进入 outputs/allure_reports/<时间戳>/allure_report/ 目录,打开 index.html 查看报告。

或使用 Allure 命令行启动本地服务:

allure serve outputs/allure_reports/<时间戳>/allure_results

Pure 报告特性

Pure 报告是框架自研的 HTML 单文件报告,主要特性:

  1. 离线可看:HTML 单文件,无需启动服务,浏览器直接打开
  2. 日志合并:自动收集 setup/call/teardown 三阶段日志,合并展示在后置处理后
  3. 媒体智能展示:无截图/录屏时对应区域不显示;有则按时间戳自动匹配
  4. 扩展区段:支持通过 pure.step() 添加自定义步骤、附件等

Pure 报告 API

Pure 报告完全参考 allure 的 API 设计,业务侧代码无需修改即可在 Pure 报告模式下工作(框架已通过 patch_allure() 自动委托)。

步骤(上下文管理器 / 装饰器)

from pytest_pure_report import pure

# 上下文管理器(自动捕获异常状态:passed/failed/broken)
with pure.step("打开登录页面"):
    page.goto("/login")

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

附件

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

# 文件附件(如截图)
pure.attach.file("screenshots/login.png", name="登录截图")

断言记录(Pure 扩展,allure 无此功能)

与原生 assert 配合,在报告中展示断言的预期值/实际值对比:

assert page.title() == "GitLink"
pure.record_equal(page.title(), "GitLink", "验证页面标题")

pure.record_contains(resp.text, "success", "验证响应包含 success")

pure.record_visible(page.locator(".avatar").is_visible(), "验证用户头像可见")

标签装饰器(与 allure 完全一致)

@pure.feature("登录")
@pure.story("成功登录")
@pure.severity(pure.severity_level.CRITICAL)
@pure.tag("smoke")
@pure.title("验证用户使用正确账号可以登录")
def test_login_success(page):
    ...

运行时动态信息

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

API 一览

API 作用
pure.step(title) 步骤(装饰器 + 上下文管理器,自动捕获状态)
pure.fixture(name) fixture 装饰器(自动追踪 setup/teardown)
pure.attach(body, ...) 添加内联内容附件
pure.attach.file(source, ...) 添加文件附件
pure.record(...) 记录断言结果(通用 API)
pure.record_equal(...) 便捷方法:相等断言
pure.record_contains(...) 便捷方法:包含断言
pure.record_visible(...) 便捷方法:元素可见性断言
pure.title/description/feature/story/... 装饰器:标签
pure.dynamic 运行时动态修改标题/标签等
pure.severity_level 严重级别常量(BLOCKER/CRITICAL/NORMAL/MINOR/TRIVIAL)
pure.attachment_type 附件类型常量(TEXT/JSON/PNG/…)

常用命令

# 使用 run.py 运行(推荐,自动生成报告)
python run.py -r pure -k login

# 直接使用 pytest 运行(调试时,不生成 Pure 报告)
pytest tests/ -v -s

# 运行特定测试
pytest tests/auth/test_login.py::TestLoginScript::test_login_success -v

# 运行特定模块
pytest tests/projects/ -v
关于

兼容 Python 脚本编写 和 YAML 数据驱动 两种模式的自动化测试框架。

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

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