我需要在程序中测试来自控制台的输入:
Main.java
-具有主要逻辑的类。
public class Main {
public static void main(final String[] args) {
final Integer dividend = new IntegerReader().fetchIntegerNumber("Input dividend: ");
final Integer divisor = new IntegerReader().fetchIntegerNumber("Input divisor: ");
System.out.println(dividend);
System.out.println(divisor);
}
}
IntegerReader.java
-从输入中读取整数。
import java.util.Scanner;
public class IntegerReader {
public Integer fetchIntegerNumber(final String message) {
System.out.print(message);
final Scanner scanner = new Scanner(System.in);
final String inputString = scanner.nextLine();
scanner.close();
return Integer.valueOf(inputString);
}
}
MainTest.java
-Main.java类的测试。
class MainTest {
private final InputStream testInputStream = new ByteArrayInputStream("2\n3".getBytes());
private final ByteArrayOutputStream testOutputStream = new ByteArrayOutputStream();
private InputStream initialInputStream = System.in;
private PrintStream initialOutputStream = System.out;
@BeforeEach
void setUpStreams() {
System.setIn(testInputStream);
System.setOut(new PrintStream(testOutputStream));
}
@AfterEach
void restoreDefaultStreams() {
System.setIn(initialInputStream);
System.setOut(initialOutputStream);
System.out.println("Test initial output stream");
}
@Test
void fetchesTextFromInput() {
Main.main(new String[]{});
final String actual = testOutputStream.toString();
assertThat(actual, is("Input dividend: Input divisor: 2\n3"));
}
}
运行测试时,出现异常:java.util.NoSuchElementException: No line found
。
如果我尝试读取第二个数字(divisor
),则会引发此异常:
final String inputString = scanner.nextLine();
如何修复测试,以免发生异常?
答案 0 :(得分:1)
您不想调用scanner.close();
,因为Scanner.close()
将关闭基础Closable
实例(此处为System.in
),因此您的虚拟测试输入流将被丢弃。
除了删除显式关闭操作外,它在运行时仍将失败:
public Integer fetchIntegerNumber(final String message) {
System.out.print(message);
final Scanner scanner = new Scanner(System.in);
final String inputString = scanner.nextLine();
// REMOVED scanner.close();
return Integer.valueOf(inputString);
}
因为返回方法将使扫描仪有资格成为GC,因此System.in
仍将关闭。
您想要的是不调用System.in.close()
。
您有两种简单的方法:阻止从扫描程序实例或直接从基础资源实例(System.in
)进行调用。
您可以用System.in
装饰FilterInputStream
。
例如:
InputStream inWithoutClose = new FilterInputStream(System.in) {
@Override
public void close() throws IOException {
}
}
然后修改方法进行测试以使其接受该对象。
答案 1 :(得分:1)
我将以接收扫描仪的方式设计IntegerReader:
public class IntegerReader {
private final Scanner scanner;
public IntegerReader(Scanner theScanner) {
this.scanner = theScanner;
}
public Integer fetchIntegerNumber(final String message) {
System.out.print(message);
final String inputString = scanner.nextLine();
return Integer.valueOf(inputString);
}
}
主类如下:
public class Main {
private Scanner scanner;
public Main(Scanner theScanner) {
this.scanner = theScanner;
}
public static void main(final String[] args) {
new Main(new Scanner(System.in)).process();
}
public void process() {
final Integer dividend = new IntegerReader(scanner).fetchIntegerNumber("Input dividend: ");
final Integer divisor = new IntegerReader(scanner).fetchIntegerNumber("Input divisor: ");
System.out.println(dividend);
System.out.println(divisor);
}
}
然后,测试看起来如下:
// this test still fails, but. ..
public class MainTest {
private final InputStream testInputStream = new ByteArrayInputStream("2\n3\n".getBytes());
private final ByteArrayOutputStream testOutputStream = new ByteArrayOutputStream();
private PrintStream initialOutputStream = System.out;
@Before
public void setUpStreams() {
System.setOut(new PrintStream(testOutputStream));
}
@After
public void restoreDefaultStreams() {
System.setOut(initialOutputStream);
System.out.println("Test initial output stream");
}
@Test
public void fetchesTextFromInput() {
Scanner scanner = new Scanner(testInputStream);
Main main = new Main(scanner);
main.process();
final String actual = testOutputStream.toString();
Assert.assertEquals("Input dividend: Input divisor: 2\n3", actual);
}
}
通过这种方式,扫描仪没有关闭。 请注意,测试不是绿色的。我用过JUnit,不知道您使用了哪种技术。
请注意:
如果我设计一个类,我不会让它依赖于System。*,而是给它一些工作流。这简化了测试。
如果在代码中的任何地方使用 new ,则需要知道该类是否需要这样做,或者是否有人,则应该由构建器或工厂创建该实例。 / p>