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

JUnit测试中如何通过ByteArrayInputStream模拟Scanner.nextFloat()输入?

问题

在使用ByteArrayInputStream和System.setIn模拟System.in进行JUnit测试时,字符串类型的菜单项输入能正常处理,但float类型的价格参数无法正确转换输入的字符串值。

Service代码

public class DailyMenuServicesImpl implements DailyMenuServices {
    private MenuPrinter menuPrinter;

    public DailyMenuServicesImpl(){
        this.menuPrinter = new MenuPrinterImpl();
    }
    @Override
    public DailyMenu addMenuItemsToMenu(DailyMenu dailyMenu) {
        Scanner scanner = new Scanner(System.in);
        MenuItem menuItem = new MenuItem();

        List<MenuItem> menuItemList = dailyMenu.getMenuItemList();
        try {
            System.out.print("\nInsert menu item name: ");
            menuItem.setNames(scanner.nextLine());
            System.out.print("Insert menu item description: ");
            menuItem.setDescription(scanner.nextLine());
            System.out.print("Insert menu item image: ");
            menuItem.setImage(scanner.nextLine());
            System.out.print("Insert menu item price:");
            menuItem.setPrice(scanner.nextFloat()); // 此处为问题点,上方代码均正常工作
            menuItemList.add(menuItem);
            dailyMenu.setMenuItemList(menuItemList);
        }catch (IllegalStateException exception){
            System.out.println(exception.getMessage());
        }catch (InputMismatchException exception){
            System.out.println(new InputMismatchException("Menu item price must be number !!!").getMessage());
        }
        return dailyMenu;
    }
}

单元测试代码

@RunWith(MockitoJUnitRunner.class)
public class DailyMenuServiceTest {
    private MenuPrinter menuPrinter;

    private DailyMenuServices dailyMenuServices;
    private final InputStream systemIn = System.in;
    private final PrintStream systemOut = System.out;

    private ByteArrayInputStream testIn;
    private ByteArrayOutputStream testOut;

    @Before
    public void init(){
        dailyMenuServices = new DailyMenuServicesImpl();
        testOut = new ByteArrayOutputStream();
        menuPrinter = new MenuPrinterImpl();
        System.setOut(new PrintStream(testOut));
    }

    @After
    public void restoreSystemInputOutput(){
        System.setIn(systemIn);
        System.setOut(systemOut);
    }
    @Test
    public void whenAddNewMenuItemsToMenu_returnNewDailyMenu(){
        List<MenuItem> menuItemList = new ArrayList<>();
        DailyMenu dailyMenu = new DailyMenu(menuItemList);
        provideInput("Pizza\nGood\nItaly\n4.56f");
        dailyMenu = dailyMenuServices.addMenuItemsToMenu(dailyMenu);

        menuPrinter.printMenu(dailyMenu);
        String expected = "Names: Pizza -  Price: 4.56$";

        assertEquals(expected,testOut.toString());
    }

    private void provideInput(String data){
        testIn = new ByteArrayInputStream(data.getBytes());
        System.setIn(testIn);
    }
}
解决方法

问题根源

  1. 非法的输入格式:测试输入中的4.56f是Java代码的float字面量语法,但Scanner.nextFloat()只识别标准十进制数字(如4.56),带f后缀会直接触发InputMismatchException。
  2. Scanner的换行残留:连续调用scanner.nextLine()后,输入流的换行符会残留,虽然当前测试未触发问题,但后续若有更多输入操作会导致异常。

修正步骤

  1. 修改测试输入内容:去掉价格后的f后缀,使用标准十进制格式:
provideInput("Pizza\nGood\nItaly\n4.56");
  1. 清理Scanner缓冲区(可选但推荐):在scanner.nextFloat()后添加scanner.nextLine(),消费掉输入流中剩余的换行符,避免后续操作异常:
menuItem.setPrice(scanner.nextFloat());
scanner.nextLine(); // 清除换行符
  1. 匹配输出时消除空白差异:由于测试输出可能包含额外换行或空格,可通过trim()统一处理:
assertEquals(expected.trim(), testOut.toString().trim());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 02:05:22