Mik*_*cki 346 java console junit
我需要为一个设计很差的旧应用程序编写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);
}
Run Code Online (Sandbox Code Playgroud)
但是当它得到格式错误的XML或者不理解它返回的请求并将null一些东西写入标准输出时.
有没有办法在JUnit中断言控制台输出?要抓住像这样的案例:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Run Code Online (Sandbox Code Playgroud)
dfa*_*dfa 543
使用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);
}
Run Code Online (Sandbox Code Playgroud)
样本测试用例:
@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());
}
Run Code Online (Sandbox Code Playgroud)
我使用此代码来测试命令行选项(断言-version输出版本字符串等)
编辑:
在System.setOut(null)测试之后调用此答案的先前版本; 这是NullPointerExceptions评论者引用的原因.
Wil*_*ill 99
我知道这是一个旧线程,但是有一个很好的库可以做到这一点:
来自文档的示例:
public void MyTest {
@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
@Test
public void overrideProperty() {
System.out.print("hello world");
assertEquals("hello world", systemOutRule.getLog());
}
}
Run Code Online (Sandbox Code Playgroud)
它还允许您捕获System.exit(-1)命令行工具需要进行测试的陷阱和其他内容.
小智 26
System.out我不会重定向,而是System.out.println()通过传递PrintStream作为协作者然后System.out在测试中使用生产和测试间谍来重构使用的类.也就是说,使用依赖注入来消除标准输出流的直接使用.
在生产中
ConsoleWriter writer = new ConsoleWriter(System.out));
Run Code Online (Sandbox Code Playgroud)
在测试中
ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));
Run Code Online (Sandbox Code Playgroud)
讨论
这样,通过简单的重构,可以测试被测试的类,而无需使用系统规则间接重定向标准输出或模糊拦截.
Mar*_*rré 13
稍微偏离主题,但是如果有些人(像我这样,当我第一次找到这个帖子时)可能对通过SLF4J捕获日志输出感兴趣,那么commons-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));
}
}
Run Code Online (Sandbox Code Playgroud)
免责声明:
log4j,log4j2并且logback都可以在瞬间,但我很高兴加入更多.@dfa答案很棒,所以我更进一步,以便测试输出块.
首先,我创建TestHelper了一个captureOutput接受烦人的类的方法CaptureTest.captureOutput方法执行设置和拆除输出流的工作.当调用CaptureOutputs test方法的实现时,它可以访问测试块的输出生成.
TestHelper的来源:
public class TestHelper {
public static void captureOutput( CaptureTest test ) throws Exception {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
ByteArrayOutputStream errContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
test.test( outContent, errContent );
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.out)));
}
}
abstract class CaptureTest {
public abstract void test( ByteArrayOutputStream outContent, ByteArrayOutputStream errContent ) throws Exception;
}
Run Code Online (Sandbox Code Playgroud)
请注意,TestHelper和CaptureTest在同一文件中定义.
然后在测试中,您可以导入静态captureOutput.以下是使用JUnit的示例:
// imports for junit
import static package.to.TestHelper.*;
public class SimpleTest {
@Test
public void testOutput() throws Exception {
captureOutput( new CaptureTest() {
@Override
public void test(ByteArrayOutputStream outContent, ByteArrayOutputStream errContent) throws Exception {
// code that writes to System.out
assertEquals( "the expected output\n", outContent.toString() );
}
});
}
Run Code Online (Sandbox Code Playgroud)
基于@dfa 的答案和另一个显示如何测试 System.in的答案,我想分享我的解决方案,为程序提供输入并测试其输出。
作为参考,我使用 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();
}
}
Run Code Online (Sandbox Code Playgroud)
为了测试它,我们可以使用以下类:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
我不会解释太多,因为我相信代码是可读的并且我引用了我的来源。
当 JUnit 运行时testCase1(),它将按照它们出现的顺序调用辅助方法:
setUpOutput(),因为@Before注释provideInput(String data),从 testCase1()getOutput(),从 testCase1()restoreSystemInputOutput(),因为@After注释我没有测试,System.err因为我不需要它,但它应该很容易实现,类似于 testing System.out。
如果你使用Spring Boot(你提到你正在使用一个旧的应用程序,所以你可能不是,但它可能对其他人有用),那么你可以使用org.springframework.boot.test.rule.OutputCapture以下列方式:
@Rule
public OutputCapture outputCapture = new OutputCapture();
@Test
public void out() {
System.out.print("hello");
assertEquals(outputCapture.toString(), "hello");
}
Run Code Online (Sandbox Code Playgroud)