This document tries to explain why to unit test ... specifically with JUnit.
Traditional testing
Traditional testing usually goes something along the lines of a developer receiving some sort of specification, implementing their own part of that and while doing so debugging any problems they may find. This in itself is an iterative process that means the developer uses a vast amount of System.out.println calls that they then remove after each problem has been solved. When the code segment has been finished, it can then be integrated with the rest of the system and then possibly a quick try to see if it fits in ok. After that it is up to the test team to find and report any bugs. At this point the developer then goes through the System.out.println process again…writing the lines, finding the problem and then removing the lines to tidy up the code.
Any other way?
All of the above is a way to get working code. However, it can be done much more efficiently…leaving the developer more time to develop rather than debug the same code again and again. This is where the JUnit test framework helps, it can make for a more stable and bug free system at the end of the development project. It then leaves test code around to help when that annoying bug keeps coming back that has been haunting you for weeks, and also for when maintenance has to be done.
Some benefits
So what are some of the benefits of spending time writing test code for something that is tested anyway? Well, let’s start by saying that whenever the words ‘test code’ are used, you might a well hear or read it as ‘reusable test code’. This is one of the key points that makes it all worthwhile. There is not one Java developer that has not written some code, used System.out.println to debug it and remove the debug code when the problem is solved. This is all well and fine for that problem at that time but what about the next time there is a problem in that piece of code? Chances are the developer will redo those lines. Wouldn’t it be nice to just start a program to run the same tests that had been written already to test that code. Now we are talking a matter of seconds instead of boring minutes re-writing more code that is going to be thrown away…yet again!
When you have some test code in place, it is easy to run the tests. Imagine that you have developed your code, written your tests and now, 6 months later, you have forgotten all about it. Then your friendly project manager comes and asks you to make a minor change to something. Yeah, we all know just how those ‘minor’ changes can introduce new ‘features’ to system…but as there is well written test code for the code that you have to change, you will be able to make the changes and ensure that all of the previous code functionality and integrity is still there. Then, you add one or two test cases of your own to cover what you have just added. Now ask yourself how well those changes could have been checked without this reusable test code!
Organising and maintaining tests
JUnit does not just allow you to write a single piece of reusable test code for testing a single item…it also allows you to group sets of tests together and gives a report of the status of runs. This means that you can test a whole application from one place. It also gives you the flexibilty of testing a subsystem or even just the package or class that you want. No need to wait for the system to be put together before any testing is done.
Quality
Quality cannot be added to a product by testing a system after it has been developed. By writing test code as early as possible in the development phase, you can prevent more bugs reaching the production phase. So by using JUnit (or any test framework) you can build quality into the product during development…which is actually the only way to make quality product code.
At some point you will wonder if your tests are any good…do they really test the code well. One aid to this is something called ‘code coverage’. This is a way to see what code has been exercised during execution. This could have been execution of the program on its own or via test cases. This means that you can instantly see how well your cases go through the code in the class(es). Most of these tools are graphical based and are very easy to use. A lot of them generate HTML reports that show the code with the lines highlighted that were exercised during the run, and how many times those lines were run. By looking at these reports, you can see if your test cases are covering your code well enough. If they aren’t, then you have a report to show which areas are missing so that you can write a test case (or cases) to cover the missing area. A by-product of this is that you can also end up finding code that no longer belongs in the system.
Another problem of a developer writing test cases for their own work is that it is easy to write simple test cases that check that the code does as it should do. A vital part of testing is to make sure code doesn’t do what it shouldn’t do…and this area is much larger than the normal ‘happy day’ usages. So, one thing that can help both you and someone else is to swap writing test code with a fellow developer. You write test code to break their code and they will write test code to break your code. Both developers’ understanding of the system grows, learning from other peoples code and competence at writing test code increases.
Things to keep in mind
JUnit has a naming convention for writing JUnit test cases
Keep test code separate from production code. This can be achieved by using the existing package name plus ‘test’ for the test code for that package. Keep in mind code visibility when doing this (what variables/methods can be seen from which class)
When you are debugging, write a test case to cover that problem so that if it shows up again, your tests will catch it. If you like, you can even write the test case that will pass when the problem is fixed and debug until that test case runs
Concentrate on writing test cases that make the code fail rather than ones that make sure that it works. You will be exercising the common paths through the software throughout development, so not so much time is needed as is to check for problems
Writing test code is no different from writing the code for the system. You are writing code to do a certain task to make sure that the system works
Don’t fall into the trap that just because there is test code that the code is bug free. What it means is that some reasonable amount of effort has been made to try to make sure that the code is bug free. It doesn’t mean that it doesn’t need more testing. Having the test code available means that you can have some level of confidence that things are going in the right direction
Last Updated Monday, November 21 2005 @ 07:38 PM CST; 1,346 Hits
IRC Hacks
I am a contributor to the IRC Hacks book released by O'Reilly in 2004. I wrote a few of the hacks, some of which were about my own software - 2 about PPF and 1 about MatchEd.