java单元测试中可用system.setin()配合bytearrayinputstream模拟标准输入:先保存原system.in,再设为含预设数据(如"123\nhello")的字节流,执行被测逻辑后务必在@aftereach或finally中恢复原输入流,以防测试污染。
在 java 单元测试中,可以通过 system.setin() 临时替换标准输入流(system.in),使其指向一个包含预设数据的 inputstream(如 bytearrayinputstream),从而让被测代码读取可控的输入,避免阻塞或依赖真实用户输入。
准备可重用的输入数据
将测试所需的输入内容组织为字符串,注意换行符需与目标平台一致(通常用 \n 即可,Java 的 Scanner 和 BufferedReader 能正确处理)。
例如,模拟两行输入:
"123\nhello"
使用 ByteArrayInputStream 替换 System.in
在测试方法开始前,把字符串转为字节数组,再包装成 ByteArrayInputStream,并传给 System.setIn():
-
保存原始输入流:调用
System.in当前值,便于后续恢复,防止测试间相互干扰 -
设置新输入流:用
System.setIn(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8))) -
执行被测逻辑:调用需要读取
System.in的方法(如含new Scanner(System.in)的代码)
务必恢复原始 System.in
测试结束后必须还原 System.in,否则可能影响其他测试。推荐在 @After 或 finally 块中执行:
- 直接赋值回原始流:
System.setIn(originalIn) - 若使用 JUnit 5,可用
@AfterEach统一处理;JUnit 4 则用@After - 避免在测试中提前调用
System.setIn(null),会导致NullPointerException
注意事项与常见陷阱
某些类(如 Scanner)会缓冲输入,若测试中未完全读完所有预设数据,后续测试可能因残留缓冲而行为异常。建议:
- 确保被测代码读取了全部预期输入(包括换行符)
- 避免在多个测试中复用同一个
Scanner实例(它不自动刷新底层流) - 对多行输入,用
nextLine()比next()更可靠,后者会跳过开头空白并停在第一个分隔符 - 如果被测方法内部新建了
Scanner(System.in),无需额外 close —— 关闭它不会关闭底层System.in
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











