如何让pytest在shell命令调用失败时正确触发测试失败
问题原因
os.system() 执行shell命令时仅返回命令的退出状态码,不会在命令执行失败(退出码非0)时主动抛出异常。pytest默认只有检测到断言失败、未捕获异常时才会将测试用例标记为失败,当前代码没有处理失败命令的非0退出码,pytest感知不到命令执行出错,因此会误判用例通过。
解决方案
方案1:兼容原有os.system()写法
POSIX系统(Linux/macOS等)下,os.system()返回的是16位整数值:高8位是进程的真实退出码,低8位是杀死进程的信号编号。提取退出码后加断言即可让pytest识别失败状态:
import os def test_that(): print("step 1: should work") ret = os.system("echo hello") assert ret >> 8 == 0, "第一个命令执行失败" print("step 2: should fail") ret = os.system("asdf_failing_non_existing_command") assert ret >> 8 == 0, "不存在的命令执行失败"
注意:Windows系统下
os.system()的返回值直接就是进程退出码,不需要移位操作,如果需要跨平台运行,更推荐使用下面的subprocess方案。
方案2:使用subprocess标准库(官方推荐,跨平台兼容)
Python官方已明确建议使用subprocess模块替代老旧的os.system()执行shell命令,模块内置了退出码自动校验能力,不需要手动解析返回值,跨平台表现一致。
只要给subprocess.run()传入check=True参数,命令执行失败(退出码非0)时就会自动抛出CalledProcessError异常,pytest捕获到未处理的异常后会直接将用例标记为失败:
import subprocess def test_that(): print("step 1: should work") # shell=True表示通过系统shell解析命令,和os.system行为一致 subprocess.run("echo hello", shell=True, check=True) print("step 2: should fail") # 命令不存在,退出码非0,自动抛异常触发用例失败 subprocess.run("asdf_failing_non_existing_command", shell=True, check=True)
- 如果不需要shell解析命令语法,建议将命令拆成参数列表传入,去掉
shell=True,可以避免shell注入风险:subprocess.run(["echo", "hello"], check=True) - 如果需要捕获命令的标准输出、标准错误内容,可以加上
capture_output=True、text=True参数:result = subprocess.run( ["echo", "hello"], check=True, capture_output=True, text=True ) print(result.stdout) # 读取命令输出的hello字符串
内容的提问来源于stack exchange,提问作者Georg Heiler
相关产品推荐
相关产品推荐

