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
相关产品推荐
相关产品推荐

