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

JUnit测试inputBoardSize方法:如何忽略Scanner输入与Sysout输出?

在JUnit测试中处理Scanner输入与控制台输出的方案

嘿,测试这段inputBoardSize()的时候确实会碰到麻烦——要么得手动输网格数卡住测试,要么控制台一堆输出干扰结果,我给你整理了一套实用的解决方案,分两步搞定:

一、模拟Scanner输入,彻底告别手动输入

方式1:依赖注入Scanner(推荐,代码更易维护)

如果你的代码里Scanner是直接在类内new的,建议改成通过构造方法注入,这样测试时能轻松替换成模拟的输入源,完全不影响原逻辑:

先改造你的业务类:

public class GameBoard {
    private Scanner scan;
    private int boardSize;
    private boolean flag = true; // 假设验证通过后会设为false

    // 构造方法注入Scanner
    public GameBoard(Scanner scan) {
        this.scan = scan;
    }

    public int inputBoardSize() {
        System.out.print("Enter the number of grids you want to play with:");
        while (flag) {
            try {
                boardSize = validateBoardSize(Integer.parseInt(scan.nextLine()));
                flag = false; // 验证通过后退出循环
            } catch (NumberFormatException e) {
                System.err.println("Please enter a number");
            }
        }
        printBoard(boardSize);
        return boardSize;
    }

    // 假设的棋盘尺寸验证方法
    private int validateBoardSize(int size) {
        if (size < 3 || size > 10) {
            System.err.println("Size must be between 3 and 10");
            flag = true;
            return -1;
        }
        return size;
    }

    private void printBoard(int size) {
        // 你的棋盘打印逻辑
    }
}

然后写测试用例,用StringReader模拟输入内容(比如先输无效值再输有效值,测试异常分支):

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.StringReader;
import java.util.Scanner;

public class GameBoardTest {

    @Test
    void inputBoardSize_WithValidInputAfterInvalid_ReturnsCorrectSize() {
        // 模拟输入:先输字符串触发异常,再输合法的5
        String simulatedInput = "not a number\n5\n";
        Scanner mockScanner = new Scanner(new StringReader(simulatedInput));
        GameBoard gameBoard = new GameBoard(mockScanner);

        int result = gameBoard.inputBoardSize();
        assertEquals(5, result);
    }
}

方式2:重定向System.in(无需修改原代码)

如果不想改动业务类的代码,直接在测试里重定向标准输入流就行,测试完记得恢复,避免影响其他测试:

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class GameBoardTest {

    // 保存原输入流,测试后恢复
    private final InputStream originalSystemIn = System.in;

    @BeforeEach
    void setUpMockInput() {
        // 模拟输入合法的4
        String mockInput = "4\n";
        ByteArrayInputStream inputStream = new ByteArrayInputStream(mockInput.getBytes());
        System.setIn(inputStream);
    }

    @AfterEach
    void restoreOriginalInput() {
        System.setIn(originalSystemIn);
    }

    @Test
    void inputBoardSize_ValidInput_ReturnsCorrectSize() {
        GameBoard gameBoard = new GameBoard(); // 原类的构造方法里new Scanner
        int result = gameBoard.inputBoardSize();
        assertEquals(4, result);
    }
}

二、屏蔽控制台输出,让测试更干净

测试时不需要看到那些提示语和错误信息,可以把System.out和System.err重定向到内存流,测试完再恢复:

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;

public class GameBoardTest {

    private final InputStream originalIn = System.in;
    private final PrintStream originalOut = System.out;
    private final PrintStream originalErr = System.err;
    private ByteArrayOutputStream capturedOut;
    private ByteArrayOutputStream capturedErr;

    @BeforeEach
    void setUpStreams() {
        // 模拟输入
        String mockInput = "5\n";
        System.setIn(new ByteArrayInputStream(mockInput.getBytes()));

        // 重定向输出到内存
        capturedOut = new ByteArrayOutputStream();
        capturedErr = new ByteArrayOutputStream();
        System.setOut(new PrintStream(capturedOut));
        System.setErr(new PrintStream(capturedErr));
    }

    @AfterEach
    void restoreStreams() {
        // 恢复所有原始流
        System.setIn(originalIn);
        System.setOut(originalOut);
        System.setErr(originalErr);
    }

    @Test
    void inputBoardSize_ValidInput_ReturnsCorrectSize() {
        GameBoard gameBoard = new GameBoard();
        int result = gameBoard.inputBoardSize();
        assertEquals(5, result);

        // 可选:验证输出内容是否符合预期
        String expectedPrompt = "Enter the number of grids you want to play with:";
        assertEquals(expectedPrompt, capturedOut.toString().trim());
    }
}

小提醒

注意你的flag变量,一定要在validateBoardSize验证通过后设为false,否则测试会进入死循环哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:02:16