Mooc.fi Java for循环本地运行正常 TMC测试报NoSuchElementException
Mooc.fi Java 练习问题排查
任务要求
- 第一部分:编写程序,打印从1到用户输入指定数值之间的所有整数
- 第二部分:新增功能,支持用户输入循环起始数值,打印起始值到终止值区间内的所有整数
问题现象
代码在本地终端手动交互运行时输出符合预期,但提交到TMC平台后WhereFromTest测试用例执行失败,报错信息为:
FAIL: WhereFromTest test NoSuchElementException: No line found
原始问题代码
import java.util.Scanner; import javax.swing.plaf.synth.SynthOptionPaneUI; public class FromWhereToWhere { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // part one System.out.println("Where to?"); int end = Integer.valueOf(scanner.nextLine()); for (int i = 1; i < end + 1; i++) { System.out.println(i); } // part two System.out.println("Where to?"); end = Integer.valueOf(scanner.nextLine()); System.out.println("Where from?"); int start = Integer.valueOf(scanner.nextLine()); for (int i = start; i < end + 1; i++) { System.out.println(i); } } }
TMC平台对应测试代码
import fi.helsinki.cs.tmc.edutestutils.MockStdio; import fi.helsinki.cs.tmc.edutestutils.Points; import fi.helsinki.cs.tmc.edutestutils.ReflectionUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.*; import static org.junit.Assert.*; @Points("02-16.2") public class WhereFromTest { @Rule public MockStdio io = new MockStdio(); @Test public void test() { int[][] pairs = {{1, 1}, {12, 8}, {50, 100}, {-2,2}}; for (int[] pair : pairs) { test(pair); } } private void test(int[] pair) { io.setSysIn(pair[0] + "\n" + pair[1] + "\n"); int len = io.getSysOut().length(); ReflectionUtils.newInstanceOfClass(FromWhereToWhere.class); FromWhereToWhere.main(new String[0]); String output = io.getSysOut().substring(len); output = output.replaceAll("[^-\\d]+", " ").trim(); String[] lines = output.split("\\s+"); int linesInOutput = (lines.length == 1 && lines[0].isEmpty()) ? 0 : lines.length; int linesCount; if(pair[0] < pair[1]) { linesCount = 0; } else { linesCount = pair[0] - pair[1] + 1; } if (linesCount != linesInOutput) { String numbersCount = (linesCount == 1) ? "number": "numbers"; fail("With the input " + pair[0] + ", " + pair[1] + " output should contain " + linesCount + " " + numbersCount + ", now it contained " + linesInOutput); } if(linesCount == 0) { return; } int firstNumber = Integer.valueOf(lines[0]); if(firstNumber != pair[1]) { fail("With the input " + pair[0] + ", " + pair[1] + " the first printed number should be " + pair[1] + ", now it was " + firstNumber); } int lastNumber = getLastNumber(output); if(lastNumber != pair[0]) { fail("With the input " + pair[0] + ", " + pair[1] + " the last printed number should be " + pair[0] + ", now it was " + lastNumber); } } private static int getLastNumber(String inputStr) { String patternStr = "(?s).*?(-?\\d+)\\s*$"; Matcher matcher = Pattern.compile(patternStr).matcher(inputStr); assertTrue("The output should be a number.", matcher.find()); int number = Integer.valueOf(matcher.group(1)); return number; } }
报错根因
- 测试用例针对第二部分功能设计,仅向程序模拟输入2行内容:第一行是区间终止值,第二行是区间起始值,对应程序仅需要读取2次用户输入。本地手动运行时用户可以按需输入足够行数的内容,因此不会触发报错,但自动化测试仅提供固定行数的模拟输入,就会触发读入失败。
- 原始代码保留了第一部分的完整逻辑,程序启动后会先读取1次输入用于第一部分固定从1开始的打印逻辑,之后第二部分还需要读取2次输入(终止值、起始值),总共需要3行输入。
- 模拟输入仅提供2行内容,代码尝试读取第三行不存在的输入时,就会抛出
NoSuchElementException: No line found错误。 - 原始代码中存在无用导入
javax.swing.plaf.synth.SynthOptionPaneUI,不影响运行但属于冗余代码。
修复方案
- 删除第一部分的冗余逻辑,程序启动后直接按第二部分要求交互:先提示输入终止值,读取后再提示输入起始值,最后打印区间内所有整数,保证程序总共仅读取2次输入,和测试的输入设计匹配。
- 删除无用的Swing相关导入语句。
- 保留原有循环判断逻辑:当起始值大于终止值时循环不执行,不输出任何内容,和测试用例的校验规则一致。
修复后的可通过测试的代码如下:
import java.util.Scanner; public class FromWhereToWhere { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("Where to?"); int end = Integer.valueOf(scanner.nextLine()); System.out.println("Where from?"); int start = Integer.valueOf(scanner.nextLine()); for (int i = start; i <= end; i++) { System.out.println(i); } } }
注:循环判断条件
i < end + 1和i <= end逻辑完全等价,后者可读性更好。
内容的提问来源于stack exchange,提问作者SkyCowie
相关产品推荐
相关产品推荐

