Python脚本输出含 致自动化测试断言失败求助
解决Python脚本输出换行符不一致导致断言失败问题
问题背景
我写了一个Python脚本,功能是读取英拉字典文件(英文单词对应多个拉丁词),生成拉英字典并输出到控制台,要求合并同一拉丁词的英文释义并去重。但自动化测试时发现脚本输出始终带\r(即换行是\r\n),和预期的纯\n换行不符,导致断言失败。试过修改PyCharm换行符设置、在代码里替换\r,都没用,甚至最小复现代码里用\n拼接输出,结果还是\r\n。
原脚本代码
import sys for filename in sys.argv[1:]: with open(filename, 'r', encoding='utf-8') as f: res_dict = {} for s in f.readlines(): cur_word = s.split()[0] translations = s.strip().replace(',', '').split()[2:] for i in translations: if i in res_dict: res_dict[i].append(cur_word) else: res_dict.setdefault(i, [cur_word]) res = [] for k, v in sorted(res_dict.items()): res.append(k + ' - ' + ', '.join(v)) print('\n'.join(res).replace('\r\n', ''))
自动化测试代码
def test_from_file(test_input_file, expected_output_file): """ 验证脚本输出正确性的测试函数 测试输入文件来自'test/resources/task3'目录: - test_input_1.txt - test_input_2.txt """ result = subprocess.run( ["python", os.path.join(SOLUTION_FOLDER_PATH, "task3.py"), test_input_file], stdout=subprocess.PIPE, ) student_output = result.stdout.decode().strip() with open(expected_output_file, "r") as expected_output_file: expected_output_content = expected_output_file.read().strip() assert student_output == expected_output_content
最小复现代码
import sys for filename in sys.argv[1:]: words = ['Hello, ', 'World!'] print('\n'.join(words))
断言错误示例
E AssertionError: assert 'baca - fruit\r\nbacca - fruit\r\nmalum - apple, punishment\r\nmulta - punishment\r\npomum - apple\r\npopula - apple\r\npopum - fruit' == 'baca - fruit\nbacca - fruit\nmalum - apple, punishment\nmulta - punishment\npomum - apple\npopula - apple\npopum - fruit'
问题原因
Windows系统下,Python的print()函数默认会把\n替换成系统默认换行符\r\n——这是因为stdout默认是文本模式,会自动做跨平台换行符转换。哪怕你用\n拼接字符串,print()输出时还是会被强制替换成\r\n。
解决方案
方法1:用sys.stdout.write()替代print()
write()不会自动添加换行符,也不会转换换行符,直接输出拼接好的内容:
# 替换原脚本中的print语句 sys.stdout.write('\n'.join(res) + '\n')
方法2:强制修改stdout的换行模式
在脚本开头添加代码,强制stdout使用\n作为换行符,关闭自动转换:
import sys # 重置stdout为指定换行模式 sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf-8', newline='\n')
方法3:全局替换所有\r字符
不管\r来自哪里,最后统一清除:
output = '\n'.join(res) print(output.replace('\r', ''))
(注意:原代码中replace('\r\n', '')只会替换完整的\r\n,但print()自动添加的是单独的\r,所以直接替换所有\r才有效)
方法4:在测试代码中统一处理换行符
如果不想修改脚本,也可以在测试时把两边的换行符统一成同一种格式:
# 处理学生输出的换行符 student_output = result.stdout.decode().strip().replace('\r\n', '\n').replace('\r', '\n') # 处理预期输出的换行符 expected_output_content = expected_output_file.read().strip().replace('\r\n', '\n').replace('\r', '\n')
修改后的完整脚本(含多文件合并+去重修复)
原脚本还有个隐藏问题:每次处理新文件都会重置res_dict,导致无法合并多个文件的内容。以下是修复后的完整代码:
import sys def main(): res_dict = {} for filename in sys.argv[1:]: with open(filename, 'r', encoding='utf-8') as f: for line in f.readlines(): line = line.strip() if not line: continue # 处理行内逗号并分割 parts = line.replace(',', '').split() if len(parts) < 3: continue eng_word = parts[0] latin_words = parts[2:] for latin_word in latin_words: # 去重添加英文释义 if latin_word not in res_dict: res_dict[latin_word] = [] if eng_word not in res_dict[latin_word]: res_dict[latin_word].append(eng_word) # 生成输出内容 output_lines = [] for latin, eng_list in sorted(res_dict.items()): output_lines.append(f"{latin} - {', '.join(eng_list)}") # 输出到控制台 sys.stdout.write('\n'.join(output_lines) + '\n') if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者Maksim Barabanov
相关产品推荐
相关产品推荐

