我正在尝试使用JUnit测试另一个程序的控制台输出。我按照here
中给出的答案这是我的JUnit类
import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.*;
public class MainTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
@Before
public void setup() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
@Test
public void test01_initTest() {
String[] arguments = {"a", "b"};
Main.main(arguments);
String expected = "hello";
assertTrue(expected == outContent.toString());
}
@After
public void cleanUpStreams() {
System.setOut(null);
System.setErr(null);
}
}
当我在eclipse中运行此程序时,我既没有看到控制台输出也没有测试运行结束。但是,如果我直接从test01_initTest()在控制台上打印输出,则测试通过。要检查Main.main()是否正在打印,我还尝试了以下代码,在这种情况下我确实看到了控制台输出
import static org.junit.Assert.*;
import org.junit.*;
public class MainTest {
@Test
public void test01_initTest() {
String[] arguments = {"a", "b"};
Main.main(arguments);
}
}
我厌倦了很多事情,但我无法弄清楚我在这里做错了什么。有人可以帮帮我。
答案 0 :(得分:1)
如果您正在测试的代码调用System.exit()
,则JUnit无法正常完成。
如果主线程终止,JUnit将挂起。
解决方法是使用SecurityManager
来阻止对System.exit()
在这个其他StackOverflow答案中,我描述了如何编写这样的SecurityManager:
Getting list of tests from JUnit command line
(此处复制的代码以防万一)。
当调用TriedToExitException
时,此SecurityManager将抛出自定义System.exit()
,并保留退出代码,以便捕获异常并测试是否使用了正确的退出代码。
/**
* A special implementation of {@link SecurityManager}
* that will throw a {@link TriedToExitException}
* if {@link System#exit(int)} is called.
* This is useful for testing main methods
* without shutting
* down the jvm running junit.
* Tests can catch {@link TriedToExitException}
* to figure out what exit code was set.
*/
public static final SecurityManager NON_EXITABLE_MANAGER = new SecurityManager(){
@Override
public void checkPermission(Permission perm) {
//allow everything
}
/**
* Throws a {@link TriedToExitException} instead of exiting.
* <p/>
* {@inheritDoc}
*/
@Override
public void checkExit(int status) {
throw new TriedToExitException(status);
}
};
public static final class TriedToExitException extends SecurityException{
private static final long serialVersionUID = 1L;
private final int exitCode;
public TriedToExitException(int exitCode){
this.exitCode=exitCode;
}
@Override
public String getMessage() {
return String.format("tried to System.exit(%d)",exitCode);
}
public int getExitCode() {
return exitCode;
}
然后在您的单元测试中,将SecurityManager替换为停止调用退出的版本(并保存旧的SecurityManager,以便我们可以在测试后恢复它)
private SecurityManager previousManager=null;
@Before
protected void replaceManager() throws Throwable {
previousManager = System.getSecurityManager();
System.setSecurityManager(NON_EXITABLE_MANAGER);
}
@After
protected void restoreManager() {
System.setSecurityManager(previousManager);
}
@Test
public void testCallToExit() throws IOException{
try{
//something that calls System.exit
fail("should call exit");
}catch(TriedToExitException e){
//make sure we get correct exit code
assertEquals(-1, e.getExitCode());
}
}