最稳妥的平台判断是用sys.platform:IS_WINDOWS = sys.platform == "win32",IS_LINUX = sys.platform.startswith("linux");命令行工具检查需预定义HAS_FFMPEG = shutil.which("ffmpeg") is not None;环境变量要用os.getenv("SKIP_SLOW", "0") == "1"避免KeyError;skipif不生效主因是条件含动态调用导致AST解析失败,应全用模块级常量。

skipif里怎么判断当前是Windows还是Linux
直接用 sys.platform 最稳妥:sys.platform == "win32" 表示 Windows,sys.platform.startswith("linux") 表示 Linux。别用 os.name(它只分 "posix" 和 "nt"),也别依赖 platform.system() 返回字符串——pytest 的 @pytest.mark.skipif 要求条件表达式在导入时就能求值,而 platform.system() 在某些打包环境(如 PyInstaller)下可能动态失败。
实操建议:
- 把判断逻辑提前写成模块级常量,避免每次导入都调用函数:
import sys IS_WINDOWS = sys.platform == "win32" IS_LINUX = sys.platform.startswith("linux") - 然后在标记中直接引用:
@pytest.mark.skipif(IS_WINDOWS, reason="仅在Linux下运行")
- 不要写成
@pytest.mark.skipif(sys.platform == "win32", ...)——虽然语法合法,但 pytest 会把它当字符串解析,导致跳过逻辑失效
如何跳过测试当某个命令行工具不存在
比如测试依赖 ffmpeg,但 CI 环境没装,不能让测试直接报错退出,得优雅跳过。
关键点:skipif 的条件必须是纯静态判断,不能在标记里调用 shutil.which() 或 subprocess.run() ——这些是运行时行为,pytest 导入阶段就报错或误判。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 在 conftest.py 或测试模块顶部预检查并缓存结果:
import shutil HAS_FFMPEG = shutil.which("ffmpeg") is not None - 再用于标记:
@pytest.mark.skipif(not HAS_FFMPEG, reason="ffmpeg未安装")
- 注意:如果测试本身会修改
PATH(比如临时加了 bin 目录),那shutil.which必须在那个上下文中执行——此时 skipif 不适用,得改用pytest.skip()在测试函数开头手动跳过
skipif中使用环境变量控制跳过逻辑
CI 场景常见需求:本地开发全跑,CI 上跳过耗时或需特殊权限的测试。
直接读 os.environ 是可行的,但要注意两点:一是环境变量可能根本不存在,二是 pytest 会把整个表达式当作字面量处理,不会帮你做异常兜底。
实操建议:
- 用
os.getenv()并提供默认值,避免KeyError:import os SKIP_SLOW = os.getenv("SKIP_SLOW", "0") == "1" - 标记写法:
@pytest.mark.skipif(SKIP_SLOW, reason="SKIP_SLOW=1")
- 别写成
@pytest.mark.skipif(os.getenv("SKIP_SLOW") == "1", ...)——这会导致 pytest 尝试在导入时执行os.getenv,而部分环境(如某些 IDE 的测试发现流程)可能尚未加载完整环境变量,结果判定为 False,跳过失效
为什么skipif有时不生效?常见陷阱
最常踩的坑不是逻辑写错,而是「跳过条件被当成字符串而非布尔表达式」。
根本原因:pytest 会尝试对 @pytest.mark.skipif(...) 中的参数做 AST 解析。如果你传的是一个无法静态求值的表达式(比如含函数调用、属性访问、变量未定义),pytest 会静默忽略该标记,测试照常执行——没有任何警告。
排查建议:
- 运行测试时加
-rs参数,看 pytest 是否输出SKIPPED记录;如果没有,大概率是条件没被识别 - 确保所有用于判断的变量都在模块顶层定义,且不依赖运行时状态
- 避免在 skipif 中使用
__name__ == "__main__"、inspect.stack()、threading.current_thread()这类绝对动态的东西 - 复杂判断(比如要查进程、读配置文件、连数据库)一律改用函数内
pytest.skip("..."),别硬塞进 skipif
pytest.skip(),也别赌 skipif 能正确解析你的表达式。


















