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);
}
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.