控制台输入和输出的JUnit测试

时间:2012-09-08 14:40:05

标签: java junit io console user-input

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

P.S。请提供一些解决方案......

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

2 个答案:

答案 0 :(得分:6)

理想情况下,提取尴尬的依赖项,以便您可以在没有它们的情况下进行测试。将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 - 但你可以使用基于doWork的{​​{1}}来测试Scanner,并根据{StringReader输出{1}},提供您想要的任何输入并检查输出。

答案 1 :(得分:0)

我遇到了类似的问题,这就是我最终要做的事情。

首先,我建议按照@ 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可以在多次使用中持续存在。