YaK:: WebLog #535 Topic : 2007-07-20 07.57.41 matt : should you upgrade to JUnit 4.x? [Changes]   [Calendar]   [Search]   [Index]   [PhotoTags]   
  [Back to weblog: pretention]  
[mega_changes]
[photos]

should you upgrade to JUnit 4.x?

I did an internal talk recently about JUnit 3.8 versus JUnit 4.3. Here's some notes and the verdict.


Anyone who has used a classic XUnit framework knows that it has some warts.

JUnit 3.8 has all of these problems, and it can cause some difficulties when trying to coach people on OO, Refactoring, and Patterns. Even if you actively point out these deficiencies and that we shouldn't do these kinds of things in our own code, there is a definite subconscious effect since the test code we write has to follow some of these anti-patterns.

JUnit 4.3 does help with most of these issues, mainly thanks to a Java 1.5 language feature called annotations. Annotations are the same as C#'s attributes:

// Java 1.5
public class SetTest {
  @Test
  public void NoDuplicatesAllowed() {
  }
}

// C#
[TestFixture]
public class SetTest
{
  [Test]
  public void NoDuplicatedAllowed()
  {
  }
}

This style has been in use in NUnit since 2002, and I'm glad it's now being in JUnit. (Note that another Java XUnit framework, TestNG , has been using this style for a few years as well.) Using Java's attributes eliminates two issues: duplicating the "test" metaphor in each test method name, and gets rid of the overloaded TestCase class altogether. Note that JUnit will run any method tagged with @Test, not requiring the containing class to be tagged at all. This seems nice, but I'm not sure how I feel about it since I haven't used it extensively on a project yet.

Without TestCase, setUp() and tearDown() methods are tagged with @Before and @After annotations, respectively. The NUnit notion of a per-fixture SetUp and TearDown are implemented in JUnit 4.3 using the @BeforeClass and the @AfterClass annotations. These annotations are honored by JUnit across inheritance hierarchies.

Assertion methods are now stored in Assert classes, just like NUnit 2.2 and below. (NUnit 2.4 has a new assertion style, described in detail in my book .) This is a great separation of concerns that should help encourage favoring class composition and delegation over inheritance.

Suites can now go back to being a collection of test classes, thanks to the @RunWith annotation that specified a test runner. The default test runner that is implcitly applied by default at runtime is the TestClassRunner.class. If you wanted to use a different default runner, like one that reverses the tests, you can do that. To specify a suite now also uses annotations, but I still would prefer a Category mechanism like NUnit uses. Hopefully categories will be included in a future JUnit release, but at least Suites are no longer overloaded.

In some performance runs, JUnit 4.3 was a little faster than JUnit 3.8 when running two classes that inherited from a common TestCase-derived class. The average runtime over 5 (five) runs after a two-run priming in IntelliJ 6.0.5 yielded 1140ms for JUnit 3.8 and 940ms for JUnit 4.3. Extrapolated over hundreds of tests, that might add up to shaving a noticeable of time off of small, fast unit tests.

If you have a large code base of existing JUnit 3.8 tests, there are some easy Find & Replace things you can do to ease the conversion to JUnit 4.3. JUnit 4.3 also includes compatibility classes so you can just drop in the new package and everything still works. I'd recommend doing the entire conversion, otherwise there just isn't much of a point.

JUnit has done a small amount of catch up with TestNG to remain relevant, but it needs an extra nudge to make it worth upgrading. JUnit's syntax for parameterized tests is just plain awkward, TestNG's is a bit prettier. That being said, converting an existing JUnit 3.8 code base to TestNG may make you buy an uzi and find a nice rooftop with which to express your feelings about the matter.

If you're starting a new Java project and are avoiding TestNG for some reason, go ahead and jump into JUnit 4.3.1. It's worth it just for the positive OO reinforcement. Upgrading the JUnit 4.3.1 on an existing JUnit 3.8 project may not give you enough benefit if you either choose to keep the 3.8 "style" or if you choose to convert your existing tests to the new style. I'd favor doing something that doesn't reinforce suboptimal OO practices that JUnit 3.8 leads you into.

For more details, see this article .

Discussion:

showing all 0 messages    

(No messages)

>
Post a new message:

   

(unless otherwise marked) Copyright 2002-2014 YakPeople. All rights reserved.
(last modified 2007-07-20)       [Login]
(No back references.)