有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用JUnit的java测试控制台输出

我正在尝试使用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()正在打印,我也尝试了下面的代码,在本例中我确实看到了控制台输出

import static org.junit.Assert.*;
import org.junit.*;

public class MainTest {
        @Test
        public void test01_initTest() {
                String[] arguments = {"a", "b"};
                Main.main(arguments);
        }
}

我做了很多事情,但我不知道我做错了什么。谁能帮帮我吗


共 (1) 个答案

  1. # 1 楼答案

    如果正在测试的代码调用System.exit(),JUnit将无法正常完成

    如果主线程终止,JUnit将挂起

    一种解决方法是使用SecurityManager来防止调用System.exit()

    在另一个StackOverflow回答中,我描述了如何编写这样一个SecurityManager:

    Getting list of tests from JUnit command line

    (代码复制到这里以防万一)

    当调用System.exit()时,此SecurityManager将抛出一个自定义TriedToExitException,并保留退出代码,以便您可以捕获异常并测试是否使用了正确的退出代码

    /**
     * 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());
    
         }
    }