我需要为一个设计很差的旧应用程序编写JUnit测试,该应用程序正在向标准输出写入大量错误消息。当getResponse(String request)方法行为正确时,它返回一个XML响应:
@BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}
@Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}
但是当它得到格式不正确的XML或不理解请求时,它返回null并将一些东西写入标准输出。
在JUnit中是否有方法断言控制台输出?捕捉以下情况:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
有点偏离主题,但如果有些人(比如我,当我第一次发现这个线程时)可能对通过SLF4J捕获日志输出感兴趣,common -testing的JUnit @Rule可能会有所帮助:
public class FooTest {
@Rule
public final ExpectedLogs logs = new ExpectedLogs() {{
captureFor(Foo.class, LogLevel.WARN);
}};
@Test
public void barShouldLogWarning() {
assertThat(logs.isEmpty(), is(true)); // Nothing captured yet.
// Logic using the class you are capturing logs for:
Foo foo = new Foo();
assertThat(foo.bar(), is(not(nullValue())));
// Assert content of the captured logs:
assertThat(logs.isEmpty(), is(false));
assertThat(logs.contains("Your warning message here"), is(true));
}
}
免责声明:
我开发了这个库,因为我找不到任何适合我自己需求的解决方案。
目前只有log4j、log4j2和logback的绑定可用,但我很乐意添加更多绑定。
基于@dfa的回答和另一个回答,说明如何测试系统。在这里,我想分享我的解决方案,给程序输入并测试其输出。
作为参考,我使用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()时,它将按照helper方法出现的顺序调用它们:
setUpOutput(),因为@Before注释
provideInput(字符串数据),从testCase1()调用
getOutput(),从testCase1()调用
restoreSystemInputOutput(),因为有@After注释
我没有测试系统。错误,因为我不需要它,但它应该很容易实现,类似于测试System.out。
使用ByteArrayOutputStream和System。setXXX很简单:
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;
@Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
@After
public void restoreStreams() {
System.setOut(originalOut);
System.setErr(originalErr);
}
示例测试用例:
@Test
public void out() {
System.out.print("hello");
assertEquals("hello", outContent.toString());
}
@Test
public void err() {
System.err.print("hello again");
assertEquals("hello again", errContent.toString());
}
我使用这段代码来测试命令行选项(断言-version输出版本字符串,等等)
编辑:
这个答案的先前版本在测试后称为System.setOut(null);这就是NullPointerExceptions注释引用的原因。