我有一个 Java 命令行程序。我想创建 JUnit 测试用例以能够模拟 System.in
。因为我的程序运行的时候会进入while循环等待用户输入。我如何在 JUnit 中模拟它?
谢谢
原文由 Noppanit 发布,翻译遵循 CC BY-SA 4.0 许可协议
我有一个 Java 命令行程序。我想创建 JUnit 测试用例以能够模拟 System.in
。因为我的程序运行的时候会进入while循环等待用户输入。我如何在 JUnit 中模拟它?
谢谢
原文由 Noppanit 发布,翻译遵循 CC BY-SA 4.0 许可协议
基于 @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()
时,它将按照它们出现的顺序调用辅助方法:
setUpOutput()
,因为 @Before
注释provideInput(String data)
,从 testCase1()
调用getOutput()
,从 testCase1()
调用restoreSystemInputOutput()
,因为 @After
注释我没有测试 System.err
因为我不需要它,但它应该很容易实现,类似于测试 System.out
。
原文由 Antônio Medeiros 发布,翻译遵循 CC BY-SA 4.0 许可协议
15 回答8.4k 阅读
8 回答6.2k 阅读
1 回答4k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
2 回答3.1k 阅读
2 回答3.8k 阅读
3 回答1.7k 阅读✓ 已解决
切换
System.in
在技术上是可行的,但一般来说,不直接在代码中调用它会更稳健,而是添加一个间接层,以便从应用程序中的一个点控制输入源.具体怎么做是一个实现细节——依赖注入的建议很好,但你不一定需要引入 3rd 方框架;例如,您可以从调用代码传递一个 I/O 上下文。如何切换
System.in
: