You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java ByteArrayInputStream测试问题:System.in重置失败引发无行异常

问题:批量运行单元测试时System.in重置失效导致NoSuchElementException

在对Java应用进行单元测试、验证异常场景时,遇到如下问题:单独运行每个测试用例均通过,但批量运行时,System.in未正确重置,后续测试抛出java.util.NoSuchElementException: No line found异常。已使用@AfterEach注解尝试恢复System.in,但未达到预期效果。

测试代码如下:

public class RacingGameTest {
    private InputStream originalInputStream = System.in;

    void initializeStreams(String inputKey) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputKey.getBytes());
        System.setIn(byteArrayInputStream);
    }

    @AfterEach
    void restoreStreams() {
        System.setIn(originalInputStream);
    }

    @Test
    void 입력이_공백일_때_IllegalBlankException_던지기() {
        // Given
        final String ONLY_BLANK = " ";

        // When
        initializeStreams(ONLY_BLANK);

        // Then
        Assertions.assertThatThrownBy(racingGame::start).isInstanceOf(IllegalBlankException.class);
    }

    @Test
    void 이름이_누락되었을_때_IllegalBlankException_던지기() {
        // Given
        final String STRING_NAMES_CONTAIN_SPACE = "name1, ,name3";

        // When
        initializeStreams(STRING_NAMES_CONTAIN_SPACE);

        // Then
        Assertions.assertThatThrownBy(racingGame::start).isInstanceOf(IllegalBlankException.class);
    }
}

原因分析

核心问题在于测试复用了持有旧System.in引用的RacingGame实例或其内部的Scanner对象:

  • 如果RacingGame类将Scanner作为成员变量(初始化时绑定了初始的System.in),即使后续通过System.setIn()重置了输入流,Scanner依然持有已被读取完毕的旧流引用。
  • 批量测试时,前一个测试的输入流被耗尽后,后续测试使用的Scanner会因流已到末尾而抛出NoSuchElementException。

解决方案

1. 确保每个测试使用独立的RacingGame实例

在@BeforeEach注解方法中初始化RacingGame,保证每次测试都使用全新的实例,其内部的Scanner会绑定当前设置的System.in:

public class RacingGameTest {
    private InputStream originalInputStream;
    private RacingGame racingGame;

    @BeforeEach
    void setup() {
        // 每次测试前获取当前System.in作为原始流
        originalInputStream = System.in;
        // 创建全新的RacingGame实例
        racingGame = new RacingGame();
    }

    void initializeStreams(String inputKey) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputKey.getBytes());
        System.setIn(byteArrayInputStream);
    }

    @AfterEach
    void restoreStreams() {
        System.setIn(originalInputStream);
    }

    @Test
    void 입력이_공백일_때_IllegalBlankException_던지기() {
        final String ONLY_BLANK = " ";
        initializeStreams(ONLY_BLANK);
        Assertions.assertThatThrownBy(racingGame::start).isInstanceOf(IllegalBlankException.class);
    }

    @Test
    void 이름이_누락되었을_때_IllegalBlankException_던지기() {
        final String STRING_NAMES_CONTAIN_SPACE = "name1, ,name3";
        initializeStreams(STRING_NAMES_CONTAIN_SPACE);
        Assertions.assertThatThrownBy(racingGame::start).isInstanceOf(IllegalBlankException.class);
    }
}

2. 修改RacingGame的实现逻辑

如果无法每次创建新实例,可修改start()方法,每次执行时重新创建Scanner,确保绑定最新的System.in:

public class RacingGame {
    public void start() {
        // 每次调用start时创建新的Scanner,使用当前的System.in
        Scanner scanner = new Scanner(System.in);
        // 后续读取输入的逻辑
        // ...
    }
}

总结

批量测试时System.in重置失效的本质是旧流引用被复用,只要确保每次测试的输入流依赖(如Scanner)都绑定最新的System.in,即可解决问题。

内容的提问来源于stack exchange,提问作者yong_ta_Park

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 04:26:35