Search code examples
junitjunit4

What's the meaning of Proctectable interface in JUnit source code?


I'm recently digging into the source code of JUnit-4.11, what confuse me is that the seemingly redundant Protectable interface. the declaration is as follows:

public interface Protectable {
    public abstract void protect() throws Throwable;
}

In the TestResult class, there is a void run(final TestCase test) method, in which a anonymous Protectable instance is realized as follows:

protected void run(final TestCase test) {
    startTest(test);
    Protectable p = new Protectable() {
        public void protect() throws Throwable {
           test.runBare();
        }
    };
    runProtected(test, p);

    endTest(test);
}

runProtected method is as follows:

public void runProtected(final Test test, Protectable p) {
    try {
        p.protect();
    } catch (AssertionFailedError e) {
       addFailure(test, e);
    } catch (ThreadDeath e) { // don't catch ThreadDeath by accident
        throw e;
    } catch (Throwable e) {
        addError(test, e);
    }
}

As we can see, what runProtected does is just executing test.runBare();, so is there any sense to the existence of Protectable interface? Why can't we just write code like below.

protected void run(final TestCase test) {
    startTest(test);
    test.runBare();
    endTest(test);
}

Solution

  • To answer your final question first, you can't use

    protected void run(final TestCase test) {
        startTest(test);
        test.runBare();
        endTest(test);
    }
    

    because it won't do what you want. JUnit manages asserts using exceptions, specifically AssertionFailedError. So, Assert.assertEquals() throws an AssertionFailedError when the two values aren't equal. So, in the above method, the endTest(test) won't get called if there is an assertion failure, which means the correct events (failure/error of the test) won't get fired, and tearDown() won't get executed.

    The Protectable interface is there to give a more generic interface to the runner, so that you don't have to hand a TestCase to the method, to allow different actions.

    As an aside, this is part of the package junit.framework.*, which is JUnit 3. JUnit 4 is where it's at, and if you want to learn, look more in the org.junit.* packages.