Java测试中System.setIn输入流异常问题求助
解决System.setIn模拟输入时后续测试抛NoSuchElementException的问题
问题原因
System.in是全局静态资源,第一个测试执行时会将模拟输入流读取至末尾。如果你的UserProfileInteraction内部复用了同一个输入读取对象(比如静态的Scanner实例),后续测试即使重新设置System.setIn,读取对象仍会绑定已耗尽的旧流,导致读取时抛出NoSuchElementException。此外,未在测试前后恢复原始System.in,也可能引发跨测试的资源污染。
解决方案
1. 测试前后恢复原始System.in
用@Before和@After注解,在每个测试执行前保存原始输入流,测试结束后恢复,避免测试间的资源干扰。
2. 确保每次测试都创建新的输入读取实例
检查UserProfileInteraction的实现,确保输入读取对象(如Scanner)是在构造方法中每次重新创建,而非使用静态或复用的实例。
修改后的测试代码示例
public class UserProfileInteractionTest { private InputStream originalSystemIn; @BeforeClass public static void setUpDB() { assertTrue(DataBaseOperations.openDBConectionTest()); } @Before public void setUpTest() { // 保存原始System.in originalSystemIn = System.in; } @Test public void registerRegisteredProfileTest(){ String input = "Test test test\ntest@gmail.com\ntestpassword\n"; InputStream in = new ByteArrayInputStream(input.getBytes()); System.setIn(in); User user = new User(); UserProfileInteraction register = new UserProfileInteraction(user); assertFalse(register.registerAccount()); } @Test public void loginRegisteredProfileTest(){ String input = "test@gmail.com\ntestpassword\n"; InputStream in = new ByteArrayInputStream(input.getBytes()); System.setIn(in); User user = new User(); UserProfileInteraction register = new UserProfileInteraction(user); assertTrue(register.loginAccount()); } @After public void tearDownTest() { // 恢复原始System.in System.setIn(originalSystemIn); } @AfterClass public static void tearDownDB() { assertTrue(DataBaseOperations.closeDBConection()); } }
关键代码修正(UserProfileInteraction示例)
错误写法(复用静态Scanner):
public class UserProfileInteraction { // 静态实例只会初始化一次,后续测试会使用已耗尽的流 private static Scanner scanner = new Scanner(System.in); public UserProfileInteraction(User user) {} public boolean registerAccount() { String name = scanner.nextLine(); // 后续测试此处会抛异常 // ... } }
正确写法(每次构造创建新Scanner):
public class UserProfileInteraction { private Scanner scanner; public UserProfileInteraction(User user) { // 每次构造都绑定当前的System.in scanner = new Scanner(System.in); } public boolean registerAccount() { String name = scanner.nextLine(); // ... scanner.close(); // 测试场景下关闭流不影响后续操作 } }
内容的提问来源于stack exchange,提问作者Jupit90
相关产品推荐
相关产品推荐

