可利用 system.setout() 临时重定向标准输出流以捕获控制台日志用于单元测试,需用 printstream 包装 bytearrayoutputstream 并在测试后还原原始流,注意编码、空白处理及并发安全。

可以利用 System.setOut() 临时替换标准输出流,将 System.out.println() 等输出捕获到字符串中,从而在单元测试中验证控制台日志内容。关键在于用 PrintStream 包装一个 ByteArrayOutputStream,重定向后再还原原始输出流,避免影响其他测试。
创建可捕获的 PrintStream
先保存原始 System.out,再构造一个基于内存字节数组的打印流:
- 用
ByteArrayOutputStream接收所有输出字节 - 用该字节数组初始化
PrintStream,确保支持println、printf等方法 - 调用
System.setOut(新 PrintStream)完成重定向
在测试中安全使用重定向
务必在测试前后恢复原始输出流,推荐用 try-finally 或 JUnit 的 @After 方法保障还原:
- 在
@Before中保存原System.out并设置新流 - 执行待测代码(触发
System.out输出) - 在
@After或 finally 块中调用System.setOut(原始 PrintStream) - 从
ByteArrayOutputStream提取字符串并断言,注意调用toString("UTF-8")避免编码问题
捕获后的内容处理技巧
捕获的字符串包含换行符和可能的多余空格,建议规范化后再断言:
- 用
.trim()去首尾空白 - 用
.replaceAll("\s+", " ")合并连续空白(如制表符、多空格) - 若需逐行校验,可用
.split("\r?\n")拆分为字符串数组 - 避免直接比对含时间戳或随机 ID 的日志,改用
contains()或正则匹配关键片段
替代方案与注意事项
System.setOut() 是全局操作,不适合并发测试或混合运行多个重定向测试:
- JUnit 5 可考虑
SystemOutputExtension(第三方扩展),自动管理生命周期 - 更健壮的做法是改造被测代码:将
PrintStream作为参数注入,测试时传入模拟对象 - 不要在生产代码中长期保留
System.setOut()调用,它会干扰日志框架和 IDE 控制台显示 - 注意
System.err是独立流,如需捕获错误输出,需单独重定向System.setErr()










