讲师中心 微信公众号
AI工具推荐 视频效率加速

如何解决 pytest 在 Jenkins 中跳过测试但本地正常执行的问题

陌静君_8443

陌静君_8443

发布时间:2025-12-31 15:30:36

|

403人浏览过

|

来源于php中文网

原创

如何解决 pytest 在 Jenkins 中跳过测试但本地正常执行的问题

pytest 在 jenkins 环境中跳过参数化测试,根本原因在于测试收集阶段(collection phase)早于工作区资源就绪,而 jenkins 清理工作区导致 `@pytest.mark.parametrize` 中调用的 `get_asset()` 提前返回空列表;需将动态资产发现逻辑移至 `pytest_sessionstart` 等会话级钩子中。

在使用 pytest 进行参数化测试时,若测试函数依赖运行时动态生成的参数(如从文件系统读取的测试资产),极易在 CI 环境(尤其是 Jenkins)中出现「本地能跑、Jenkins 跳过」的诡异现象。其本质并非 Jenkins 本身限制,而是 pytest 的测试收集机制与CI 工作流时序发生冲突所致。

? 问题根源解析

pytest 在执行任何测试前,会先进入 collection 阶段:静态扫描所有测试模块,解析 @pytest.mark.parametrize、@pytest.fixture 等装饰器,并立即求值其中的参数表达式(如 get_asset())。此时:

  • 若 get_asset() 依赖磁盘上的 asset/ 目录,则该目录必须在 collection 阶段已存在且可访问;
  • Jenkins 默认启用 “Delete workspace before build starts”,导致每次构建开始时工作区为空;
  • 因此 collection 阶段调用 get_asset() 返回空列表 → pytest 认为无参数可迭代 → 整个 test_app_launch_asset 被静默跳过(显示为 skipped 或甚至不显示);
  • 而手动登录 Jenkins 机器后执行命令时,工作区已被前次构建残留的 asset/ 填充,故 get_asset() 正常返回 → 测试正常执行。
⚠️ 注意:这不是 get_asset 函数逻辑错误,而是执行时机错配——它被当作“编译期常量”求值,实则应是“运行期动态数据”。

✅ 正确解决方案:使用 pytest 会话级钩子预加载参数

应避免在 @parametrize 中直接调用 IO 密集型函数。推荐将资产发现逻辑提前至 pytest_sessionstart(在 collection 之前执行),并将结果缓存到 config 对象中供后续使用:

Pub Session Logs
Pub Session Logs

使用 jq 搜索和分析您自己的会话日志。还有 50+ 模型用于图像生成、视频生成、语音合成、语音识别、音乐、聊天等

下载
# conftest.py
import pytest
from pathlib import Path

def get_asset() -> list[Path]:
    """安全版资产发现:确保路径存在且可读"""
    asset_dir = Path(__file__).parent / 'asset'
    if not asset_dir.exists():
        return []
    return [
        p for p in asset_dir.iterdir()
        if p.is_file() and 'need_to_skip_asset' not in p.name
    ]

def pytest_sessionstart(session):
    """在测试收集前执行:预加载资产列表并挂载到配置"""
    assets = get_asset()
    session.config._metadata['available_assets'] = assets  # 可选:用于报告
    # 将资产列表注入全局变量或 session 属性(推荐)
    session.assets = assets

# 在测试文件中改写参数化逻辑
@pytest.fixture(scope='session', autouse=True)
def available_assets(request):
    """提供会话级 fixture,确保资产列表在测试中可用"""
    return request.session.assets

@pytest.mark.parametrize('asset', [], indirect=True)  # 占位符,实际由 fixture 提供
def test_app_launch_asset(app_binary, asset, available_assets):
    """实际测试逻辑 —— 参数由 fixture 动态注入"""
    print(f'Application: {app_binary}')
    print(f'Asset: {asset}')

    applib.execute(
        cmd=[str(app_binary), str(asset)],
        timeout=15,
    )

但更简洁、符合 pytest 惯例的方式是:完全弃用 @parametrize 的函数调用形式,改用 indirect + fixture 组合:

# test_app.py
import pytest

@pytest.fixture(params=[])  # 空占位,真实参数由 conftest.py 注入
def asset(request):
    # 此处可访问 session.assets(需在 conftest.py 中设置)
    session = request.session
    if not hasattr(session, 'assets'):
        pytest.skip("No assets found — check asset directory existence")
    return session.assets[request.param]

# 重写 parametrize:传入索引而非对象
@pytest.mark.parametrize('asset', list(range(100)), indirect=True)
def test_app_launch_asset(app_binary, asset):
    print(f'Application: {app_binary}')
    print(f'Asset: {asset}')
    applib.execute(cmd=[str(app_binary), str(asset)], timeout=15)

不过最推荐的工业级实践是:在 conftest.py 中定义一个 session-scoped fixture,返回完整资产列表,再在测试中通过 for 循环显式遍历(牺牲少量 pytest 原生参数化语法糖,换取完全可控性):

# conftest.py
import pytest
from pathlib import Path

@pytest.fixture(scope='session')
def all_assets():
    asset_dir = Path(__file__).parent / 'asset'
    if not asset_dir.exists():
        pytest.skip(f"Asset directory missing: {asset_dir}")
    return [
        p for p in asset_dir.iterdir()
        if p.is_file() and 'need_to_skip_asset' not in p.name
    ]

# test_app.py
def test_app_launch_asset(app_binary, all_assets):
    """单测试函数内遍历所有资产 —— 完全规避 collection 时序问题"""
    for asset in all_assets:
        print(f'Running on asset: {asset}')
        applib.execute(cmd=[str(app_binary), str(asset)], timeout=15)

? 关键注意事项

  • ✅ 永远不要在 @pytest.mark.parametrize(...) 的参数表达式中执行 IO 操作(如读文件、查数据库、调用外部命令);
  • ✅ pytest_sessionstart 和 pytest_configure 是仅有的两个在 collection 之前触发的钩子,适合做预热准备;
  • ✅ Jenkins 构建日志中若看到 collected 0 items,基本可断定 collection 阶段参数源为空;
  • ✅ 在 conftest.py 中添加 print() 或日志输出,验证钩子是否被触发(注意 Jenkins 控制台编码与缓冲);
  • ✅ 本地调试时,可临时在 get_asset() 开头加入 assert Path('asset').exists(),快速暴露环境差异。

通过将动态数据获取逻辑与 pytest 的生命周期对齐,即可彻底解决 Jenkins 下测试“神秘跳过”的问题,让 CI 行为与本地开发保持一致、可预测、可调试。

热门AI工具

更多
UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

LibLibAI
LibLibAI Hot

一款AI视频创作工具,主要用于国内领先的AI创意平台,以海量模型、低门槛操作与“创作-分享-商业化”生态,让小白与专业创作者都能高效实现图文乃至视频创意表达,适合需要提升相关任务效率的用户。

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

2620

2023.09.27

python print用法与作用
python print用法与作用

本专题整合了python print的用法、作用、函数功能相关内容,阅读专题下面的文章了解更多详细教程。

249

2026.02.03

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

5924

2023.10.24

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

580

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

876

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

1866

2025.08.19

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

2731

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

845

2023.12.29

FrankenPHP集成Laravel详细教程
FrankenPHP集成Laravel详细教程

本专题提供FrankenPHP集成Laravel的详细配置指南,全面解析运行原理、开发环境搭建、Caddyfile配置、Octane工作模式、数据库连接、队列任务、定时任务和生产环境优化,解决部署过程中常见的报错与兼容性问题。

0

2026.10.08

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
LLVM Programmer’s Manual
LLVM Programmer’s Manual

共0课时 | 0人学习

Conan 包创建教程
Conan 包创建教程

共0课时 | 0人学习

Visual Studio 入门指南
Visual Studio 入门指南

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn