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

JUnit单元测试多用户输入:NoSuchElementException问题排查

解决单元测试中Scanner多次读取输入流抛出NoSuchElementException的问题

问题描述

单元测试一个需要两次用户输入的方法时,抛出NoSuchElementException,提示第二个scanner.nextLine()未检测到元素。测试代码中已用\n分隔两次输入,但无效。

测试代码:

@Test
public void testMultipleValidMenuInput(){
    ByteArrayInputStream inputStream = new ByteArrayInputStream("TestString\n1".getBytes());
    System.setIn(inputStream);
    sampleAccount.enrolCourse(sampleList);
    Assert.assertEquals("FirstExpectedLine\nSecondExpectedLine", outputStreamCaptor.toString().trim());
}

目标方法核心代码:

public void enrolCourse(courseList listOfCourses){
    // ...
    Scanner scanVar = new Scanner(System.in); // 第一个Scanner实例
    String searchTerm = scanVar.nextLine();
    // ...
    if (applicableCourses.size() > 1) {
        // 调用menuSelect方法
    }
}

private boolean menuSelect(ArrayList<Course> courseArray, boolean enrolOrWithdraw) throws DuplicateClassException{
    Scanner scanVar = new Scanner(System.in); // 第二个Scanner实例
    // ...
    int inputVar = Character.getNumericValue(scanVar.nextLine().charAt(0)); // 抛出异常的位置
    // ...
}

问题原因

核心问题是重复创建Scanner实例读取同一个System.in输入流:

  • 第一个Scanner在enrolCourse中读取第一行输入后,输入流的指针已移至末尾(输入流仅包含"TestString\n1"两行内容)。
  • 第二个Scanner在menuSelect中尝试读取时,输入流已无剩余内容,调用nextLine()直接抛出NoSuchElementException。

解决方案

方案1:复用同一个Scanner实例

将Scanner作为参数传递给menuSelect方法,避免重复创建:

public void enrolCourse(courseList listOfCourses){
    ArrayList<Course> applicableCourses = new ArrayList<Course>();
    Scanner scanVar = new Scanner(System.in); // 仅创建一次Scanner
    String searchTerm = scanVar.nextLine();
    boolean termFound = false;
    for (Course e: listOfCourses.getCourseList()) {
        if (e.getCourseName().toLowerCase().contains(searchTerm.toLowerCase())){
            applicableCourses.add(e);
            System.out.println(e.getCourseName() + " has been found.");
            termFound = true;
        }
    }
    if (!termFound) {
        System.out.printf("Courses containing %s has not been found. %n", searchTerm);
    } else if (applicableCourses.size() == 1) {
        // 原有逻辑不变
    } else if (applicableCourses.size() > 1) {
        boolean selectionNotMade = true;
        do {
            try{
                // 将Scanner作为参数传入menuSelect
                selectionNotMade = menuSelect(scanVar, applicableCourses, true);
            } catch (DuplicateClassException e){
                System.out.println(e);
            }
        } while(selectionNotMade);
    }
}

// 修改方法参数,接收外部传入的Scanner
private boolean menuSelect(Scanner scanVar, ArrayList<Course> courseArray, boolean enrolOrWithdraw) throws DuplicateClassException{
    for(int i = 0; i < courseArray.size(); i++) {
        System.out.printf("%s ) %s %n", i+1, courseArray.get(i).getCourseName());
    }
    System.out.println("Please select a number according to which course you would like.");
    try {
        int inputVar = Character.getNumericValue(scanVar.nextLine().charAt(0));
        // 原有逻辑不变
    }
    catch (IndexOutOfBoundsException e) {
        System.err.println("Selection could not be made.");
        return true;
    }
}

方案2:将Scanner作为类成员变量

如果类中多个方法都需要读取输入,可将Scanner声明为类成员变量统一管理:

public class YourAccountClass {
    private Scanner scanVar = new Scanner(System.in); // 类成员Scanner实例
    private List<Course> enrolmentList = new ArrayList<>();

    public void enrolCourse(courseList listOfCourses){
        // 直接使用成员变量scanVar读取输入
        String searchTerm = scanVar.nextLine();
        // 后续逻辑不变
    }

    private boolean menuSelect(ArrayList<Course> courseArray, boolean enrolOrWithdraw) throws DuplicateClassException{
        // 直接使用成员变量scanVar读取输入
        int inputVar = Character.getNumericValue(scanVar.nextLine().charAt(0));
        // 后续逻辑不变
    }
}

额外注意事项

  • 不要随意关闭Scanner(除非确认不再使用System.in),关闭Scanner会同时关闭底层的System.in输入流,导致后续无法读取。
  • 单元测试中若多次涉及System.in,需在测试前后恢复原输入流,避免测试间干扰:
private InputStream originalIn;

@BeforeEach
void setUp() {
    originalIn = System.in;
}

@AfterEach
void tearDown() {
    System.setIn(originalIn);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:27:47