All entries for Monday 15 May 2006
May 15, 2006
JUnit 4.0; whats all the fuss (aka jumping on the annotations bandwagon)
Writing about web page http://www.instrumentalservices.com/index.php?option=com_content&task=view&id=45&Itemid=52
I love junit. I think it is probably one of the best pieces of software around. It easily allows developers to follow one of the best methodologies around; test driven development, or at least development with tests :)
I do not think JUnit is perfect; there are bugs (google for more details…), and I was really hoping JUnit 4.0 would solve some of them.
Unfortunately, JUnit 4.0 has “fixed” all the wrong things :( Of course, this is only my opinion, and I am very grateful for all their hard work, but I am dissappointed.
Basically; the main difference between JUnit 3.0 and 4.0 is the infrastructure used to setup and define tests…JUnit 3.0 uses abstract classes and naming conventions; JUnit 4.0 uses annotations. Arguably having to not extend a base class is always good (less pervasive), but I think this is less so with unit tests (see later)
In a nutshell Rather than having
public class MyTestClass extends TestCase {
private Object myObject;
public void setUp() {
myObject = new myObject();
}
public void testFirstAssumption() {
assertTrue("hello world", myObject.getHelloWorld());
}
public void tearDown() {
myObject = null; // completely unneccessar, but for illustration
}
}
now you would do:
public class MyTestClass {
private Object myObject;
@Before public void setUp() {
myObject = new myObject();
}
@Yest public void firstAssumption() {
assertTrue("hello world", myObject.getHelloWorld());
}
@After public void tearDown() {
myObject = null; // completely unneccessary, but for illustration
}
}
whats the difference; I am using annotations instead of naming conventions….what has it bought me in real terms... absolutely nothing. I still have to explicitly mark a test method, the setupMethod, tearDown method etc., I just use annotations instead of naming conventions.
I am of course being entirely unfair….you can do more things with the annotations like having more than one setup method, commenting out test methods (@Ignore), indicating your test expects an exception (@Test(expected=yourException) but so what?
The only thing of value is the @test(timeout=X) method which natively indicates that the test must execute within X milliseconds. Very useful; but there are already extensions to do this.
Extending framework classes are bad
It is true that frameworks which require you to extend a base class are so 1980s :) but with unit tests, I actually don’t think it is such a bad thing…. the problem is that you cannot extend your own class because Java doesn’t support multiple inheritence (for better or worse…). However, the point is that unit tests are supposed to be small atomic tests which test a single thing. They are not supposed to be complicated, hierarchical object graphs which build layer upon layer of logic. If I cannot understand what is happening from looking at a single unit test…I consider that unit test less than optimal. I know a lot of my coworkers dissagree with me on this, but I would rather see code duplication in a test method rather than a parameterised method … simply for understandability. Let me say it again, I think any unit test method should be self contained for readability. Yeah; go on, flame away :) The worst thing you can have is unit tests breaking because you have modified another unit test ;) Unit tests breaking because of changes to domain code is good, breaking because of changes to unit tests are bad. Very bad…
So, after that lengthy paragraph, the fact that JUnit 3.0 imposes a relatively inflexible infrastructure in which to write your unit tests is not so much a good thing, but it does prevent you over complicating your unit tests.
Summary
So, is JUnit 4.0 is a dissappointment, no (despite the previous paragraph). Do I think JUnit 4.0 is a massive improvement; no. I do see how annotations are useful (timing, repeating etc.), but I feel somewhat underwhelmed :)