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

Java井字棋测试问题:仅首个输入生效,后续输入无响应

Java井字棋测试问题:仅首个输入生效,后续输入无响应

兄弟,我仔细看了你的代码和问题描述,核心问题出在多个Scanner实例共享同一个System.in输入流上,咱们一步步拆解解决:

问题根源

你在InputSelector里每次创建实例都会new一个新的Scanner(System.in),而System.in是单向字节流——当第一个Scanner读取输入中的3之后,它会把流内内容缓存起来,后续新建的Scanner再读取时,流里已经没有剩余内容了,自然就抛出No line found错误。

手动运行时没问题是因为控制台输入是实时的,每次读取都会等待用户输入;但测试用的ByteArrayInputStream是一次性静态流,多个Scanner实例会把流的读取状态彻底搞乱。

解决方案

1. 复用同一个Scanner实例

重构InputSelector,让它接收外部传入的Scanner,而非每次自行新建,这样所有读取操作都用同一个Scanner,就能按顺序读取输入的3和2:

public class InputSelector {
    private final Scanner scanner;

    // 构造函数注入Scanner,方便测试时传入自定义输入流
    public InputSelector(Scanner scanner) {
        this.scanner = scanner;
    }

    // 保留默认构造,供正常运行时使用
    public InputSelector() {
        this(new Scanner(System.in));
    }

    public int computerOrHuman() {
        return Integer.parseInt(scanner.nextLine());
    }

    // 你的boardType()方法也要改成用这个scanner读取
    public int boardType() {
        return Integer.parseInt(scanner.nextLine());
    }
}

2. 让依赖类接收统一的InputSelector

修改Board类,通过构造函数注入InputSelector,避免每次创建新实例:

public class Board {
    private char[][] values;
    private int rows;
    private int columns;
    List<Character> winnersX = new ArrayList<>();
    List<Character> winnersO = new ArrayList<>();
    private final InputSelector inputSelector;

    // 带参数的构造,供测试用
    public Board(int rows, int columns, InputSelector inputSelector) {
        this.rows = rows;
        this.columns = columns;
        this.values = new char[rows][columns];
        this.inputSelector = inputSelector;
    }

    // 默认构造,正常运行时使用
    public Board(int rows, int columns) {
        this(rows, columns, new InputSelector());
    }

    public int computerOrHuman() {
        return inputSelector.computerOrHuman();
    }

    // ...其他方法
}

3. 调整测试代码,用统一的Scanner读取输入

测试时创建一个基于ByteArrayInputStream的Scanner,并传递给所有需要的类,确保输入被依次读取:

@Test
void testRowX() {
    // given
    String testInput = "3\n2";
    ByteArrayInputStream inputStream = new ByteArrayInputStream(testInput.getBytes());
    Scanner testScanner = new Scanner(inputStream);
    InputSelector testInputSelector = new InputSelector(testScanner);

    // when
    OutputComputer outputComputer = new OutputComputer();
    outputComputer.gameStart();
    outputComputer.gameType();
    
    int boardSize = testInputSelector.boardType(); // 读取第一个输入3
    Board testBoard = new Board(boardSize, boardSize, testInputSelector);
    
    StartGame startGame = new StartGame();
    // 建议修改runGame方法,直接传入Board实例,避免内部再创建新的InputSelector
    startGame.runGame(testBoard);

    String whoWin = "Won X";

    // then
    // 注意原测试里的拼写错误:把"Won X"写成了"Wona X"
    assertEquals("Won X", whoWin);
}

另外要注意:你原测试里的assertEquals有拼写错误,"Wona X"应该改成"Won X",不然测试肯定会失败。

额外提醒

如果不想大改代码,也可以在测试时只设置一次System.setIn,并且确保整个测试流程中只用一个Scanner实例,但构造注入的方式更灵活,也更符合测试驱动开发的思想,方便后续扩展测试场景。


备注:内容来源于stack exchange,提问作者Robert Wyszynski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:44:32