JUnit测试控制台输入和输出

3

我只有一个main方法。如何使用JUnit检查System.out.println()并自动替换Scanner输入值?

附注:请提供一些解决方案...

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int[] arr = new int[4];

    for (int i = 0; i < arr.length; i++) {
        arr[i] = scanner.nextInt();
    }

    for (int i = 0; i < arr.length; i++) {
        int res = 0;
        int k = 0;
        int num = arr[i];
        /*.....*/
        System.out.println(num);
    }
}

我想学习如何使用它。 - Pretto
2个回答

7
理想情况下,应该提取出棘手的依赖项,以便你可以在没有它们的情况下进行测试。只需将main更改为:

public static void main(String[] args) {
  doWork(new Scanner(System.in), System.out);
}

// TODO: Rename to something meaningful
public static void doWork(Scanner input, PrintStream output) {
  // Remainder of code
}

考虑使用Writer而非PrintStream作为output的替代方案。

这样你就不需要对main进行单元测试了,但你可以使用基于StringReaderScanner测试doWork,并使用基于StringWriter的输出,提供任何你想要的输入并检查输出。


2
我该如何使用它来实现例如多个输入对应多个信息提示的功能? - CodyBugstein
我有同样的问题。如果你找到了什么,请告诉我! - Aman
@Aman:抱歉,我之前可能没有看到这个评论。你需要提供一个“Scanner”,它返回用户预期输入的所有值。 - Jon Skeet
1
谢谢。但是我使用了System Rules库 https://stefanbirkner.github.io/system-rules/。 - Aman

2
我遇到了类似的问题,这是我最终采取的解决方法。
首先,我建议按照@Jon-Skeet的建议,不要使用类的main(String[])方法,而是创建一个单独的方法。
然后,您可以让该方法将InputStream作为参数传入,然后在该方法内部创建一个Scanner对象,该对象使用传递的InputStream作为其源。这样,当调用该方法时,您可以传递任何InputStream,例如System.in(下面进行详细说明)。
package my.package;

import ...;

public class MyClass
{
    public static void myMethod(InputStream inputStream)
    {
        Scanner inputScanner = new Scanner(inputStream);

        // Do stuff with the Scanner such as...
        String input = inputScanner.nextLine();
    
        System.out.println("You inputted " + input);
    }
}

现在,在您的生产源代码中,您可以调用myMethod并将System.in作为参数传递,如下所示:myMethod(System.in); 然后在您的单元测试中,您可以通过ByteArrayInputStream创建模拟输入值:
package my.package;

import ...;

public class MyClassTest
{
    @Test
    void testMyMethod()
    {
        // Simulates a user inputting the string "Mock input" and hitting enter
        assertDoesNotThrow(myMethod(new ByteArrayInputStream("Mock input\n".getBytes())));
    }
}

看,现在你有了一种方法来传递你的方法模拟输入,而且整体上更加模块化。

我只是想指出,不要过多地涉及到它,当使用 System.in 时,需要小心关闭它,在单元测试中使用输入流时,需要小心重用对同一 InputStream 的引用,因为它的状态可能会跨越使用而持续存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接