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

新手上路,请多包涵

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

谢谢

原文由 Noppanit 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 869
2 个回答

切换 System.in 在技术上是可行的,但一般来说,不直接在代码中调用它会更稳健,而是添加一个间接层,以便从应用程序中的一个点控制输入源.具体怎么做是一个实现细节——依赖注入的建议很好,但你不一定需要引入 3rd 方框架;例如,您可以从调用代码传递一个 I/O 上下文。

如何切换 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);
}

原文由 McDowell 发布,翻译遵循 CC BY-SA 2.5 许可协议

基于 @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.err 因为我不需要它,但它应该很容易实现,类似于测试 System.out

原文由 Antônio Medeiros 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题