The unit test war : JUnit vs TestNG
What is unit testing anyway?
If you’re in contact with Java development, as a developer, an architect or a project manager, you can’t have heard of unit testing, as every quality method enforces its use. From Wikipedia:
“Unit testing is a test (often automated) that validates that individual units of source code are working properly. A unit is the smallest testable part of an application. In procedural programming a unit may be an individual program, function, procedure, etc., while in object-oriented programming, the smallest unit is a method, which may belong to a base/super class, abstract class or derived/child class. Ideally, each test case is independent from the others.”
Unit tests have much added value, apart from validating the working of your classes. If you have to change classes that you didn’t develop yourself, you should be glad to have them… because if they fail, it would instantly alert you of a failure: you won’t discover the nasty NullPointerException you just coded in production!
Before the coming of testing frameworks (more later), the usual testing was done:
- either manually, eventually traced on an external document,
- in the
mainmethod of the class.
Both of the options were dead wrong. In the first case, it was impossible to know what test was passed, if the trace was up-to-date. In the second case, all your classes would become executable in the production environment, not a very good design.
The coming of JUnit
Then came Erich Gamma (yes, the same who wrote about design patterns!) and his magical framework JUnit. JUnit just industrializes your unit tests without messing with your code base proper. You just write a class in the right way and presto, you can launch JUnit to pass the tests. The test classes can be localized anywhere you please so you don’t have to ship them along with your application.
Even better, now that JUnit has gained widespread recognition, every tool proposes to plug into it:
- most IDEs (Eclipse, NetBeans, what have you) propose integrated plugins,
- Ant provides a JUnit task that can run from your build,
- Event better, if you put your tests in a specific Maven foldern, namely
src/test/java, they are run automatically and if a test fails, it breaks the build.
Well, it can’t get better, can it? Yet, when using JUnit extensively, you can’t avoid to see some drawbacks.
First of all, JUnit doesn’t allow for parameters. For example, let’s say that you want to test the following generic method:
In the JUnit framework, you would have to implement at least two test methods, one for integers and one for decimal point numbers, and better, one for each
Number type. The most rational use would be to code a single test method and to call it many times, each time passing a different set of parameters.
JUnit test classes can be grouped into packages like any regular classes. But I would like to group my tests into a nicely organized hierarchy to know precisely where my tests are failing. For example:
- a functional group,
- a technical group
- and a gui group.
JUnit doesn’t provide an answer.
Time cost of running tests
Followers of Agile methodologies preach that builds, including unit tests, should be run in less than 10 minutes. I’m not sure if that’s the good limit, but I agree that a build should be the fastest possible.
What about failed tests? In my opinion, if your build fails because of failed tests, it should be at the earliest time possible. What’s the point of running more tests if the build is fated to fail? That’s only a waste of time.
More precisely, I want my framework not to run all my database tests if a test method informs me the database can’t be accessed whatever the reason. A nice feature would be to have natively such a dependency mechanism in the testing framework.
Where do we go from here?
I recently discovered another testing framework. The name is TestNG: the authors freely ackonwledge their framework is directly inspired from JUnit. It provides every functionality of JUnit and solves all the aforementioned problems.
- the Java 5 version of TestNG uses exactly the same annotation names as JUnit,
- if you want to keep your JUnit tests, TestNG can run JUnit tests,
- if you don’t want, specific converter classes make the migration a breeze,
- there are Eclipse and IDEA plugins available,
- TestNG tests are run natively by Maven.
In conclusion, I have nothing against JUnit, on the contrary. It did a marvelous job in making unit testing easy and we, as developers, owe their authors. But it is not a final product: it can be enhanced (see all the extensions people made). TestNG is such an enhancement, I can’t recommend enough its use.