JUnit:如何模拟 System.in 测试?

2022-08-31 15:22:35

我有一个Java命令行程序。我想创建JUnit测试用例,以便能够模拟。因为当我的程序运行时,它将进入while循环并等待用户的输入。如何在 JUnit 中模拟它?System.in

谢谢


答案 1

从技术上讲,可以切换 ,但一般来说,在代码中不直接调用它,而是添加一个间接层,以便从应用程序中的某个点控制输入源会更可靠。确切地说,你如何做到这一点是一个实现细节 - 依赖注入的建议很好,但你不一定需要引入第三方框架;例如,您可以从调用代码传递 I/O 上下文。System.in

如何切换 :System.in

String data = "Hello, World!\r\n";
InputStream stdin = System.in;
try {
  System.setIn(new ByteArrayInputStream(data.getBytes()));
  Scanner scanner = new Scanner(System.in);
  System.out.println(scanner.nextLine());
} finally {
  System.setIn(stdin);
}

答案 2

基于@McDowell的答案另一个显示如何测试System.out的答案,我想分享我的解决方案,为程序提供输入并测试其输出。

作为参考,我使用JUnit 4.12。

假设我们有这个程序,它只是将输入复制到输出:

import java.util.Scanner;

public class SimpleProgram {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print(scanner.next());
        scanner.close();
    }
}

为了测试它,我们可以使用以下类:

import static org.junit.Assert.*;

import java.io.*;

import org.junit.*;

public class SimpleProgramTest {
    private final InputStream systemIn = System.in;
    private final PrintStream systemOut = System.out;

    private ByteArrayInputStream testIn;
    private ByteArrayOutputStream testOut;

    @Before
    public void setUpOutput() {
        testOut = new ByteArrayOutputStream();
        System.setOut(new PrintStream(testOut));
    }

    private void provideInput(String data) {
        testIn = new ByteArrayInputStream(data.getBytes());
        System.setIn(testIn);
    }

    private String getOutput() {
        return testOut.toString();
    }

    @After
    public void restoreSystemInputOutput() {
        System.setIn(systemIn);
        System.setOut(systemOut);
    }

    @Test
    public void testCase1() {
        final String testString = "Hello!";
        provideInput(testString);

        SimpleProgram.main(new String[0]);

        assertEquals(testString, getOutput());
    }
}

我不会解释太多,因为我相信代码是可读的,并且我引用了我的来源。

当 JUnit 运行时,它将按照帮助程序方法出现的顺序调用它们:testCase1()

  1. setUpOutput(),因为注解@Before
  2. provideInput(String data),调用自testCase1()
  3. getOutput(),调用自testCase1()
  4. restoreSystemInputOutput(),因为注解@After

我没有测试,因为我不需要它,但它应该很容易实现,类似于测试。System.errSystem.out


推荐