如何使用Pytest测试基于argparse开发、带命令行参数的程序输出
Pytest测试命令行程序的两种实现方案
方案1:直接调用程序入口(优先推荐)
如果你的程序用argparse实现参数解析,只需稍作调整把核心逻辑封装为可接收参数列表的main函数,就能在测试时直接模拟传入命令行参数,不需要启动子进程,执行速度更快、调试更方便。
你的程序示例(myprog.py)调整后结构:
import argparse def main(args=None): parser = argparse.ArgumentParser() parser.add_argument("-i", required=True, help="输入参数") parser.add_argument("-o", required=True, help="输出参数") # args为None时自动读取系统命令行参数,测试时可手动传入参数列表 parsed_args = parser.parse_args(args) # 你的核心业务逻辑 res = f"输入值:{parsed_args.i},输出值:{parsed_args.o}" print(res) return res if __name__ == "__main__": main()
对应的pytest测试代码:
import pytest from myprog import main def test_myprog_single_case(): # 等价于命令行执行 myprog -i value_a -o value_b test_args = ["-i", "value_a", "-o", "value_b"] run_res = main(test_args) # 验证返回结果符合预期 assert run_res == "输入值:value_a,输出值:value_b"
方案2:子进程调用完整程序(无需修改原有代码)
如果你不想调整原有程序结构,可以用subprocess模块直接启动子进程执行完整命令,捕获输出后验证,不需要调用内部函数。
不要使用os.system,它只能获取程序退出码,无法捕获标准输出/错误内容
测试代码示例:
import pytest import subprocess def test_myprog_cli_call(): # 执行命令,捕获输出,text=True指定返回字符串而非字节 run_res = subprocess.run( ["myprog", "-i", "value_a", "-o", "value_b"], capture_output=True, text=True ) # 先验证程序正常退出,退出码为0 assert run_res.returncode == 0 # 验证输出符合预期,strip()用于去除末尾换行符 assert run_res.stdout.strip() == "输入值:value_a,输出值:value_b"
如果程序没有加到系统PATH,把命令列表替换为["python", "你的myprog.py文件的绝对/相对路径", "-i", "value_a", "-o", "value_b"]即可。
多组参数批量测试技巧
如果需要测多组参数组合,可以用pytest的参数化装饰器,不用重复写测试函数:
import pytest from myprog import main @pytest.mark.parametrize("input_val, output_val, expect_res", [ ("value_a", "value_b", "输入值:value_a,输出值:value_b"), ("test123", "res456", "输入值:test123,输出值:res456"), ("abc", "123", "输入值:abc,输出值:123"), ]) def test_myprog_multi_cases(input_val, output_val, expect_res): test_args = ["-i", input_val, "-o", output_val] assert main(test_args) == expect_res
内容的提问来源于stack exchange,提问作者Bruce Banner
相关产品推荐
相关产品推荐

