为何test_inputstream测试未按预期失败?Java Mock输入流疑问
问题
我是Java新手,原本计划通过自定义InputStream模拟系统输入流,但当前test_inputstream_fails_on_mismatch测试中,断言预期值为"quiffdt",而MockInputStream提供的输入是"quit",测试却成功了,不符合预期。请问这种Mock输入流的方式是否有误?我是否在实现方向上完全错误?
相关代码
package com.skilldistillery.lordo.app; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.io.InputStream; import java.util.Scanner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class UITest { Scanner sc = new Scanner(System.in); InputStream mockInputStream; @BeforeEach void init() { // This will run once before any of the test methods in the class. mockInputStream = new MockInputStream(); System.setIn(mockInputStream); } @Test void test_inputstream_fails_on_mismatch() { assertEquals("quiffdt", sc.nextLine()); } } class MockGame implements CLIGame { @Override public void pushEvent(GameEvent event) {} } class MockInputStream extends InputStream { private byte[] inputBytes; private int position = 0; public MockInputStream() { String input = "quit" + System.lineSeparator(); this.inputBytes = input.getBytes(); } @Override public int read() throws IOException { if (position < inputBytes.length) { return inputBytes[position++]; } else { return -1; } } @Override public void close() throws IOException { super.close(); } }
原因分析与解决办法
你的问题核心是Scanner对象的初始化时机错误:
- 你在类成员位置直接创建了
Scanner sc = new Scanner(System.in);,此时System.in还是JVM默认的标准输入流,并非你在@BeforeEach里替换的MockInputStream。 - 当
@BeforeEach执行替换系统输入流时,Scanner已经绑定了原始输入流,完全没用到你Mock的流,所以你的断言根本没读取到Mock的"quit",测试结果毫无意义。
修正步骤
- 调整Scanner初始化时机:不要在类成员位置创建Scanner,而是在替换完系统输入流之后再初始化:
class UITest { Scanner sc; InputStream mockInputStream; @BeforeEach void init() { mockInputStream = new MockInputStream(); System.setIn(mockInputStream); sc = new Scanner(System.in); // 替换流之后再初始化Scanner } @Test void test_inputstream_fails_on_mismatch() { assertEquals("quiffdt", sc.nextLine()); // 现在会读取Mock的"quit",测试会失败,符合预期 } }
- 简化Mock实现(可选):作为新手,没必要自己写MockInputStream,直接用JDK自带的
ByteArrayInputStream即可:
@BeforeEach void init() { String mockInput = "quit" + System.lineSeparator(); System.setIn(new ByteArrayInputStream(mockInput.getBytes())); sc = new Scanner(System.in); }
这样省去了自己实现read()方法的麻烦,减少出错概率。
总结
你的Mock方向没错,只是Scanner初始化时机不对,导致没用到替换后的Mock输入流。调整顺序后,测试就能正常验证输入是否匹配了。
内容的提问来源于stack exchange,提问作者user14924651
相关产品推荐
相关产品推荐

