如何测试有多行输出的Python函数并匹配捕获的标准输出内容
测试匹配标准输出的解决方案
报错根因
- 你编写的
targe_region函数命中覆盖条件分支时,执行的是return print(key, values),print()函数本身没有返回值,默认返回None,所以直接断言函数返回值必然匹配失败 - 命中分支时的提示内容是输出到标准输出(stdout)而非作为函数返回值返回,只有未覆盖的分支才会返回提示字符串
调整测试的方案
你用的测试框架如果是pytest,直接用内置的capsys fixture捕获标准输出即可,修改后的测试用例如下:
def test_target_region(capsys): # 传入pytest内置的capsys fixture捕获标准输出/错误 """ chr20 3 4 Neg2 0 - 127477031 127478198 0,0,255 chrX 1 50 Neg3 0 - 127478198 127479365 0,0,255 chrX 50 100 Pos5 0 + 127479365 127480532 255,0,0 """ BED = Read_file("./test_bed_file_with_errors4.bed") data_loaded = BED.load_data() bed_data = Bed_tools(data_loaded) user_input2 = "chrX:55" chro = user_input2.split(":")[0] position = user_input2.split(":")[1] # 先调用函数,输出内容会被capsys捕获 res = bed_data.targe_region(data_loaded, chro, position) # 读取捕获到的标准输出,strip()用于去掉首尾多余的空白、换行符 captured_stdout = capsys.readouterr().out.strip() # 分别校验返回值和输出内容,覆盖全部分支逻辑 # 命中覆盖分支时返回值为None assert res is None # 校验输出内容和预期一致,注意删除预期字符串里多余的缩进 assert captured_stdout == """Your position is covered by this bed file chrX [50, 100]"""
如果你用的是unittest框架,可以用mock.patch捕获标准输出,示例如下:
from io import StringIO from unittest.mock import patch def test_target_region(self): BED = Read_file("./test_bed_file_with_errors4.bed") data_loaded = BED.load_data() bed_data = Bed_tools(data_loaded) user_input2 = "chrX:55" chro = user_input2.split(":")[0] position = user_input2.split(":")[1] with patch('sys.stdout', new=StringIO()) as fake_stdout: res = bed_data.targe_region(data_loaded, chro, position) captured_stdout = fake_stdout.getvalue().strip() assert res is None assert captured_stdout == """Your position is covered by this bed file chrX [50, 100]"""
可选优化(允许修改原函数的场景)
如果函数不是不可修改的公共依赖,更合理的写法是把输出内容作为返回值返回,同时保留打印逻辑,既不影响原有功能,也方便测试和上层逻辑调用:
def targe_region(self, bed, chro, position): """ Tool 1: Look is position is covered by the Bed file input. """ for key, value in bed.items(): if key == chro: for values in value: if int(position) in range(values[0], values[1]): output = f"Your position is covered by this bed file\n{key} {values}" print(output) return output return "Your position is not covered by this bed file"
修改后你原来的断言逻辑可以直接生效,不需要额外捕获标准输出。
内容的提问来源于stack exchange,提问作者user14618562
相关产品推荐
相关产品推荐

