如何从控制台测试多个输入?

时间:2018-11-12 12:59:52

标签: java testing input

我需要在程序中测试来自控制台的输入:

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();

如何修复测试,以免发生异常?

2 个答案:

答案 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,不知道您使用了哪种技术。

请注意:

  1. 如果我设计一个类,我不会让它依赖于System。*,而是给它一些工作流。这简化了测试。

  2. 如果在代码中的任何地方使用 new ,则需要知道该类是否需要这样做,或者是否有人,则应该由构建器或工厂创建该实例。 / p>