This is an article in response to Bob Gregory’s ‘Creating a culture of quality’. It aims to address the difference between unit testing and functional testing, and show the benefit of developers testing their own code.
To begin, there is a big difference between unit testing and functional testing. Unit tests are written by the developer to test the code that they are working on. Ideally, a new unit test is written for each new addition or change to the code. They generally concentrate on smaller sections or ‘units’ of the code. These could range from individual methods, to classes.
A functional test is generally not performed by the developer. These test the product from a customer perspective and show that it is complete and fully functioning. I would agree with Bob to the extent of saying that, a developer who has written the code should not be performing the functional test. However, I would disagree with his comment that developers should not test their own code.
Having a complete set of tests to test your own code is an absolutely fantastic wall of defence to have. If you keep on running the suite of tests for every single change that you make, you can quickly see if you have broken another part of your code. They also create a natural suite of regression tests, which make refactoring a hell of a lot safer.
The other important advantage of unit testing is that it gives any new developer instant access to a code base. Just imagine that you start a new job, and you are given a large code base to look at. How would you normally go about this? Poke around a bit, perform a build, step through with a debugger? With unit tests, you can step write into various different functions of the code immediately, and quickly gain a greater understanding of it. In my current company, I have used this technique to train up all the new starters, and have had every single one of them fixing bugs on their first day (the bugs might not have been completed on the first day, but at least they made a good start!).
There have been a couple of incidents where I have found that a developer made changes to a code base, but did not run the unit tests afterwards. When checking the code out of CVS to check their changes, I found that the code compiled fine, the changes looked good, but the unit tests failed. It is amazingly easy to break a bit of your code when you make a change, but unit tests can help to pick this up. It actually makes you feel quite good when you see a previous test fail after a change, as you know that your tests are working.
Bob made the following comment on testing apps:
‘While your app is small, it’s easy to test, but as you start to add more features, you create dependencies between features. This allows changes in one part of the system to ripple, in subtle ways, and bugs can appear in what appears to be a completely unrelated area.’
I have a couple of responses to this. Firstly I would say that if you have a big system with no tests, it can seem incredibly daunting to put them in, but it is completely possible. Often this means that you have to take a step up from unit tests, and write some integration tests. This is when parts of the software are combined and tested as a group. This is obviously not as easy as an isolated unit test, but can be done. The general practice of doing this is to ‘mock up’ the desired state of the system and run the test. From experience, I have found that it is possible to mock up a lot more than you would think. I managed to mock up several parts of a Struts application, and mock up a database by using an in memory database in my unit tests. There are loads of things out there to help with this. Java examples are HSQLDB (a fantastically usefully database that can run as an in memory instance), Cactus (can be used to test Web Frameworks) and Easy Mock (which can be used to Mock up an interface). Spring also has an inbuilt testing framework which can test web apps. This leads me onto the next subject of loose coupling.
Spring is a very modular based framework which encourages loose coupling between components. Loose coupling will really help reduce the dependencies between features, which cause the ‘unwanted ripples’. You don’t have to use Spring to keep an application loosely coupled, it’s just a very good example. Joshua Bloch (Effective Java) was talking about loose coupling ages ago, in the sense that you should use abstraction to hide code implementation. Loosely coupled code is so much easier to test. When working on a larger system, if unit/integration testing is used from the start, the system automatically becomes loosely couple, due to the need to test it. When working on a large system with no tests, you’ll just have to mock up the state a bit to get the tests in, then gradually refactor to a more loosely couple model when more comfortable with it. It might take a bit of work, but is definitely worth it.
So, to conclude: Remember that unit testing is not functional testing. Functional testing is generally done by a QA team, and is extremely important. But, unit testing should not be forgotten. Here is a recap of the benefits mentioned:
- Unit testing provides a natural set of regression tests, which get bigger with every new test added.
- Unit tests give easy access to a code base for a new developer, which can drastically speed up development.
- Unit testing makes refactoring much safer, and gives you more confidence when doing so.
- Unit testing can pick up code that has been unknowingly broken by a new change
- Integration testing is a good step towards functional testing, and can replicate some of the functional tests that are done by QA.