Why Evangelising Unit Testing Needs to Stop

Tags:
After reading Is the popularity of unit tests waning? I thought about my own evangelism of unit testing. The practice of unit testing is well established in most languages and yet many Java programmers I have worked with don't do it.

When Java was first released and C++ challenged it was clear what class of problems that Java made go away. The garbage collector and lack of pointers removed two major problems that every C/C++ programmer had come across, errors with pointer arithmetic and the fail to free memory. Since both of these bugs where painful to track down something that removed them completely was a good idea. Even developers early in their careers suffered these problems and Java as an offering was obviously solving the problem. Indeed the same is true today comparing Ruby on Rails to J2EE development, where the differences in line count and productivity are night and day. Of course just like the rise of Java performance suffers somewhat eith Rails and there are things you can't do in Rails. The same was true when Java came out and some wondered how we would get by without using the Windows API and pointers. The value proposition of languages and many frameworks are obvious.

Part of Java's success was its copying of C like syntax. Many technologies are built to make a better mouse trap, language churn and frameworks are good examples. The subtle implications come much later after using the new tool for a while and new problems appear. Modern unit testing builds on a long history of automated tests going back at least as far as Smalltalk, its not so much that its a new technique or technology. The modern unit testing frameworks for Rails are better than basic JUnit but they are still pretty basic. I think this is a C syntax like wooing where they try to keep the framework as simple as possible so that writing the tests is very familiar.

It seems that only 20% of developers are convinced by the vague benefits of unit testing. Of course those which are convinced are also the guys writing in Ruby, looking at Scheme and generally building the modern web. The other 80% of developers don't seem to be feeling the unit testing vibe. I think that is because the class of problems that it solves is not obvious. Indeed its something that can apparently can be solved with quality assurance teams and every development team has those! Passing the work of testing to the testers is much easier and less work for a busy developer.

Worse still is the cost of unit testing. The obvious cost of adding extra code is easy to see, but also there is the cost of designing and implementing the code in a different decoupled way. Adding mocks and other nastiness only adds to the ick feeling of writing unit tests. This can add complexity and certainly adds to development time. It can be argued that decoupled code is better but then when was anything other than working software the goal important? Most systems descend into untouchable code anyway and management won't allow the developers to change anything for fear it will all unravel or add significant bugs and worse require a complete regression test, which would take months. I have seen countless clients throw away old systems and start rewriting because they could not keep adding functionality any more. The code had rotted beyond what could be maintained and the testing effort had gone up linearly with the amount of functionality and so the cycle starts again.

Unit tests are just like JavaDoc, we all know they should be written and are "important". But just like JavaDoc there is no obvious benefit to an individual developer. Sure I know that someone trying to read the code later would benefit from JavaDoc and unit tests will catch other peoples bugs in the future. Why would I want to help the idiot in the future that touched my code. Certainly doubling the effort to writing the code to add these benefits seems like a really high price to be paying.

Yet evangelism is still strong and popularity with good developers still high. Of all the good developers I have had the fortune of working with all of them but one wrote good unit tests. The one exception almost proved the rule as he wrote great integration tests, he was just rubbish at unit tests. Every developer I've met which sucked (about 85%) didn't write unit tests. I have unfortunately met some useless developers who claim to write tests, although they are very poor at it.

Whether unit testing really helps write better code is hard to say. The costs are obvious but the benefits are softer than most evangelists would like to admit, productivity remains unmeasurable. Any practice that adds lines of code and yet claims to reduce overall effort is going to struggle to gain acceptance. Unit testing has become the required documentation of the future, just as UML died a death unit testing will have to go the same way. That doesn't mean its no use, it simply represents the best solution we've found to a class of problems we've so far failed to find the best solution to. Just as Java (nearly) killed memory leaks so will something in the future kill the need for unit tests. In the mean time the best way to reduce the class of bugs that unit testing fixes is to write unit tests.

The evangelising of unit tests to some extent has to stop. Right now its hit the perfect point of identifying the top 20% of developers and making the other 80% easy to spot. Indeed I think such a practice is unlikely to really break into the mainstream any time soon due to its weak proposition. So if all the evangelism could just go away that would be just perfect.
1
Average: 1 (1 vote)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jesper Nordenberg replied on Thu, 2008/05/29 - 4:15am

The benefit of unit testing obviously depends on how good the tests are. Writing good tests is not easy and the tools needs to be improved to facilitate this task (libraries like JUnit are not helping much). One step in the right direction is libraries like QuickCheck for Haskell, ScalaCheck for Scala and Reductio for Java with closures. The thing with these libraries is that you describe the properties of your classes/functions/methods and then these properties are automatically tested.

Mark Thornton replied on Thu, 2008/05/29 - 4:34am

While we are waiting for the unit test killer, I think there remains much that could be done to make unit tests easier to implement. Constructing the initial state and comparing the results are sometimes major exercises.

 

doclolieven replied on Thu, 2008/05/29 - 7:01am

Unit testing is a cost, I'll grant you that. But it's a short term cost, especially in huge evolving applications. In smaller application the cost is harder to recover, as the relative weight is larger than with larger projects. In large to huge projects, unit tests are indispensable, since they provide some measure of protection when it comes to regression. What would you rather have: changing an algorithm and testing each case by yourself, or have a predefined unit test that tests the algorithms contract?

A lot of programmers suck at unit testing because they fail to write unit-testable code, that's my experience. Those who write nicely separated code, don't have any problems writing unit tests.

To finish I was quite astounded by the sentence:

 ... just as UML died a death...

Excuse me? And how may I ask are you modelling your system? Flowcharts? Indeed, it'll be a lot harder to unit test a system without a solid analysis and design. And I have yet to see a system without a UML schema to provide documentation on some level. UML's not dead, but you're right, it's suffering the same 'disease' as unit testing, there's no gain on the short term. But the costs of not having one or both will be killing you in the end.

 

Jess Holle replied on Thu, 2008/05/29 - 8:10am

Two comments:

  1. Far too much time and faith seems to be put into unit tests at non-module boundaries.  If you have a reusable module of code with a well-defined, stable API and contract, then asserting that via a unit test is great.  Doing so for particularly hairy internal algorithms or classes is also great.  Doing so at every arbitrary class or package is generally non-sense -- it increases the effort required to make what should be internal changes that shouldn't bother anyone as long as the module tests pass.  If somehow you don't have modules, then integration tests are it [though you'd have to question the lack of any modules...]
  2. Arbitrarily changing code to facilitate unit testing is generally a bad idea.  If this leads one to discover inappropriate coupling at a module boundary and a decision to change the API based on other engineering requirements, that's well and good.  If, however, you're doing it just to allow use of mocks with some notion that this will somehow improve your code against other requirements, that's just silly.  First off, use a better mocking framework, e.g. jmockit, so you often don't have to change existing code to mock -- stop using antiquated tooling like easymock and separate the mocking religion from your API design.  Secondly, just because it meets the needs of a mocking framework does not mean the API has improved by other metrics.  [For instance, stuff that really should be final and/or non-public may become non-final or public just to allow for mocking -- thereby reducing API quality.]

tlaurenzo replied on Thu, 2008/05/29 - 9:42am

Good article.  It scratched an itch I have about unit testing.

Your analogy relating unit testing to manual memory management resonated with me and helped resolve some dissonance I have in my own mind about the topic.  As a people leader and professional developer, I tow the line, insisting on and writing good unit tests, but I have never been able to shake the feeling that how the topic is typically approached should be telling us something about how we write software -- similar to how the obsession with manual memory management in C++ told us something and led to a better way (at least for a lot of common domains).

I started to write a long diatribe about what I feel is right and wrong about unit testing, but then I realized that's what you just did so I deleted it and decided to shut up.

So thanks for the analogies -- they've given me something to ponder. 

Michael Hoffman replied on Thu, 2008/05/29 - 11:45am

Thank you, please stop evangelizing unit testing. Fixing all this broken code keeps me in business!

As with everything, unit testing is good in moderation. If a developer is very new, they should be writing lots of strong, elaborate unit tests. This makes her/him a better developer later on and solidifies their code. If you are more seasoned? You can get away with small tests in Java because you are probably writing more solid code and can see the potential code traps just by looking at the code. Ive seen very strong application components that were unit tested through Eclipse by running the debugger and changing the parameters as the code churned along. Nothing like setting a variable to null and watching what happens! So I dont disagree with you that evangelizing unit testing is the right answer, I think we need to do a better job of seeing what unit testing is needed and who needs to do more of it. Just my two cents.

  

gjferrier replied on Thu, 2008/05/29 - 2:44pm

I've got to disagree with this last point.  What happens when that newbie developer is asked to adapt the seasoned developers code, when he (the seasoned developer) has long since left the building?  We cannot assume a single owner of any piece of code - those days are long gone.  I can't think of anything worse than being asked to fix some code which doesn't have a set of unit tests which don't go green first time I run them.  Writing unit tests is great to educate, but its certainly not only for the individual writing the code today. 

Ricky Clarkson replied on Thu, 2008/05/29 - 5:21pm

Reductio doesn't depend on Java with closures, it just is easier to read that way.

Steven replied on Thu, 2008/05/29 - 10:34pm

i find the constant use of evangelizing a tad annoying.

however, i did enjoy this article. thanks for the read.

Christopher Lim replied on Fri, 2008/05/30 - 5:39am

To answer the question: "Why would I want to help the idiot in the future that touched my code?"

More often than not the idiot in the future will be the developer itself.

Tim Lavers replied on Fri, 2008/05/30 - 7:49am

Part of the problem is that unit test promotions generally involve such simple tests. You know, a basic class with no user interface or any other complications. That's one of the reasons we wrote this:

http://www.packtpub.com/java-swing-extreme-testing/book

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.