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

为何test_inputstream测试未按预期失败?Java Mock输入流疑问

问题

我是Java新手,原本计划通过自定义InputStream模拟系统输入流,但当前test_inputstream_fails_on_mismatch测试中,断言预期值为"quiffdt",而MockInputStream提供的输入是"quit",测试却成功了,不符合预期。请问这种Mock输入流的方式是否有误?我是否在实现方向上完全错误?

相关代码

package com.skilldistillery.lordo.app;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class UITest {

    Scanner sc = new Scanner(System.in);
    InputStream mockInputStream;
    
    @BeforeEach
    void init() {
        // This will run once before any of the test methods in the class.
        mockInputStream = new MockInputStream();
        System.setIn(mockInputStream);
    }

    @Test
    void test_inputstream_fails_on_mismatch() {
        assertEquals("quiffdt", sc.nextLine());
    }

}
class MockGame implements CLIGame {
    @Override
    public void pushEvent(GameEvent event) {}
}

class MockInputStream extends InputStream {

    private byte[] inputBytes;
    private int position = 0;

    public MockInputStream() {
        String input = "quit" + System.lineSeparator();
        this.inputBytes = input.getBytes();
    }

    @Override
    public int read() throws IOException {
        if (position < inputBytes.length) {
            return inputBytes[position++];
        } else {
            return -1;
        }
    }
    
    @Override
    public void close() throws IOException {
        super.close();
    }
}
原因分析与解决办法

你的问题核心是Scanner对象的初始化时机错误:

  • 你在类成员位置直接创建了Scanner sc = new Scanner(System.in);,此时System.in还是JVM默认的标准输入流,并非你在@BeforeEach里替换的MockInputStream。
  • 当@BeforeEach执行替换系统输入流时,Scanner已经绑定了原始输入流,完全没用到你Mock的流,所以你的断言根本没读取到Mock的"quit",测试结果毫无意义。

修正步骤

  1. 调整Scanner初始化时机:不要在类成员位置创建Scanner,而是在替换完系统输入流之后再初始化:
class UITest {
    Scanner sc;
    InputStream mockInputStream;
    
    @BeforeEach
    void init() {
        mockInputStream = new MockInputStream();
        System.setIn(mockInputStream);
        sc = new Scanner(System.in); // 替换流之后再初始化Scanner
    }

    @Test
    void test_inputstream_fails_on_mismatch() {
        assertEquals("quiffdt", sc.nextLine()); // 现在会读取Mock的"quit",测试会失败,符合预期
    }
}
  1. 简化Mock实现(可选):作为新手,没必要自己写MockInputStream,直接用JDK自带的ByteArrayInputStream即可:
@BeforeEach
void init() {
    String mockInput = "quit" + System.lineSeparator();
    System.setIn(new ByteArrayInputStream(mockInput.getBytes()));
    sc = new Scanner(System.in);
}

这样省去了自己实现read()方法的麻烦,减少出错概率。

总结

你的Mock方向没错,只是Scanner初始化时机不对,导致没用到替换后的Mock输入流。调整顺序后,测试就能正常验证输入是否匹配了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:25:01