Java 在涉及Console.readline()的情况下测试void main的输出

Java 在涉及Console.readline()的情况下测试void main的输出,java,junit,console,mockito,Java,Junit,Console,Mockito,我需要通过输出(in system.out)junit测试现有代码 由于console.readline正在等待用户输入,我发现它将在console.readline()中停止,从而阻止我获取输出 有办法做到这一点吗?是否可以使用Mockito或其他方法进行测试?对于单元测试来说,main方法不是一个很好的候选方法。它只是一个应用程序的入口点。也许,您需要将类重构为某种依赖注入。例如: public class Something { private final LinesProvid

我需要通过输出(in system.out)junit测试现有代码

由于console.readline正在等待用户输入,我发现它将在console.readline()中停止,从而阻止我获取输出


有办法做到这一点吗?是否可以使用Mockito或其他方法进行测试?

对于单元测试来说,
main
方法不是一个很好的候选方法。它只是一个应用程序的入口点。也许,您需要将类重构为某种依赖注入。例如:

public class Something {

    private final LinesProvider linesProvider;

    public Something(LinesProvider linesProvider) {
        this.linesProvider = linesProvider;
    }

    public void sayHello() {
        String str = linesProvider.readLine();
        System.out.println("halo "+str);
    }

    public static void main(String args[]) {
        new Something(new LinesProvider() {
            private final Console console = System.console();
            @Override
            public String readLine() {
                return console.readLine();
                }
        }).sayHello();
    }
}

interface LinesProvider {
    String readLine();
}
然后,您可以测试系统输出,如下所示,尽管这不是一个好的实践。相反,尝试将I/O逻辑与应用程序逻辑分开:

public class TestSomething {

    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    private PrintStream printStream = new PrintStream(outputStream, true);

    @Before
    public void setUp() {
        System.setOut(printStream);
    }

    @Test
    public void test() {
        new Something(new LinesProvider() {
            @Override
            public String readLine() {
                return "Vasya";
            }
        }).sayHello();

        assertEquals("halo Vasya" + System.getProperty("line.separator"), new String(outputStream.toByteArray()));
    }
}

测试与
System.console()
一起工作的代码几乎是不可能的,因为您在测试中总是重新运行
System.console()
。另外,
Console
是没有公共构造函数的最终类

我建议与
Console
的编写者和读者一起工作,并测试与编写者和读者一起工作的代码

public static void main(String args[]) {
   Console console = System.console();
   BufferedReader reader = new BufferedReader(console.reader());
   main2(reader, console.writer(), args);
}

static void main2(BufferedReader reader, Writer writer, String args[] {
   String str = reader.readline();
   System.out.println("halo"+str);
}

可以使用库的
StandardOutputStreamLog
规则测试输出到
System.out
。但是在您的代码中,写入
控制台的编写器要比写入
系统容易得多。out

使用JMockit mocking API,以下测试将起作用:

@Test
public void testMyApp(@Mocked final Console console)
{
    new NonStrictExpectations(System.class) {{
        System.console(); result = console;
        console.readLine(); result = " test";
    }};

    OutputStream output = new ByteArrayOutputStream();
    System.setOut(new PrintStream(output));

    MyApp.main(new String[0]);

    String lineSep = System.getProperty("line.separator");
    assertEquals("halo test" + lineSep, output.toString());
}
@Test
public void testMyApp(@Mocked final Console console)
{
    new NonStrictExpectations(System.class) {{
        System.console(); result = console;
        console.readLine(); result = " test";
    }};

    OutputStream output = new ByteArrayOutputStream();
    System.setOut(new PrintStream(output));

    MyApp.main(new String[0]);

    String lineSep = System.getProperty("line.separator");
    assertEquals("halo test" + lineSep, output.toString());
}