Further JUnit

Following on from Bill’s excellent comments, and chats with Geoff and Alan, I agree that there is more than one way to consider JUnit. One is JUnit as a standalone unit testing tool, with some extensions bolted on. The other is JUnit as a framework. As a developer’s unit testing tool, JUnit works very well, and does exactly what it says on the tin. As a framework, it is not ideal. It started life as a Java implementation of the SUnit smalltalk test tool, and has been refactored over time, to the point where it is at least possible to write plug-in extensions, if not necessarily easy.

Alan made the excellent point that JUnit could (should?) be simply a straightforward test framework that makes assertions and fires events. The mechanism of orchestrating the tests and handling the events could be entirely separate. Which would possibly have made SuiteRunner easier to implement as a layer on top of JUnit.

Stop dissing JUnit

JUnit seems to have come under fire recently, with articles such as this, and posts like this one from Geoff and this one from Cedric. The Artima article complains that JUnit’s reporting features are underdeveloped, and Cedrid & Geoff want to see success messages as well as failure ones.

JUnit is a ‘unit testing’ tool. Its supposed to be run many times a day. Its output is supposed to be transient. All the tests are supposed to pass all the time. Red bar / green bar. Pass or fail. If all the tests are passing it should remain silent. If a test fails, print a useful message. If you have a suite of thousands of tests, how easy is it to find 1 failure message if its mired inside 999 inane ‘test passed, foo does equal foo’ printouts?

The same goes for reporting. It is actually possible to get detailed reports from JUnit as XML, which can be processed by an ANT task to produce nice looking web pages, but if its being used correctly, all the tests would always be at 100%, as you don’t commit if any of the tests are failing, right?

Bolting on extra features blurs the line between functional testing and unit testing, and I for one am happy for JUnit to remain clearly focussed on doing one job very well, which it does admirably.

Side note: The Artima article is called ‘Why we refactored JUnit’. Following neatly on from my earlier post, what they did was neither big-R or little-R. What they actually did was write a brand new, JUnit testcase compatible tool from the ground up. Refactoring is defined as ‘improving the design of existing code’. In the strictest sense the only people who can refactor JUnit are the JUnit committers and contributers, and the result would still have been JUnit, with all the same behaviour, but with a cleaner internal structure.

Refactoring refactored

Something Alan said a few weeks ago has just bubbled to the surface: there appear to be two main ways that people think about refactoring. I’m going to call them ‘Refactoring’ (big ‘R’) and ‘refactoring’ (small ‘r’).

The apparently more common usage is the big-R form, Refactoring as a task in its own right. Typical comments would be “We have to spend the next two weeks Refactoring this system”. The small-r form is done as part of everyday programming activities, at the same level as writing statements and method calls. Nobody says, “Today my tasks will include writing for-loops, methods and if-else statements.” (Although that is a great way of describing your activities without actually saying anything about what you will be doing.)

The XP / Test-first crowd tend to think of refactoring in the small-r sense. Its just one piece of the Test-Code-(r)efactor cycle that they go through many times a day. In this way (in a perfect world), the code is kept clean and lean enough that Refactoring (big-R) is never required. Having to plan a Refactoring session for some code probably means that its in what the XP books call ‘Refactoring debt’ (its like oxygen debt for software). The system wasn’t refactored mercilessly enough (if at all) while it was being grown, and, just like a human in oxygen debt, progress slows down and pain increases, until it becomes necessary to stop and do something about it, in a big Refactoring session.

I am of the opinion that just as aerobic exercise (eg. jogging) is less painful and can be done for longer than anaerobic exercise (eg. sprinting), its better to keep to the discipline of refactoring as you go (ideally as part of the test-code-refactor cycle), and try to minimise the incidences of Refactoring required (during which customer-visible progress tends to slow or stop).

RAM to rent, excellent rates

Reading ‘The Mythical Man Month’ currently. Cool fact I learned today: in 1969 or thereabouts, it cost $12 a month to rent a Kb of RAM. So I could charge out the machine I’m typing this on for approximately $10,000,000 a month, at 1969 prices. Taking inflation into account, its probably more like half a billion dollars. Every month.

Any takers?

Service temporarily unavailable

Realised the other day that javablogs has become my news aggregator. This means that I’ve lost track of those blogs not on it, Russ’s being one. Too much pure java probably isn’t good for you.

So here’s something completely different:

Earth
Air
Water
Fire

If that all seems too energetic, there’s always Drink.

If you absolutely must be coding, try these:

http://www.perl.com/
http://www.python.org/
http://www.erlang.org/
http://www.scheme.org/
http://www.haskell.org/

And of course…
Intercal: home of the coolest programming construct ever. Who needs GOTO when you have… COME FROM!

For those times when java is just too damn boring.

Agile code

Tony Bowden: Understanding Nothing: Writing Agile Code

The issue of ‘agile code’ has been occupying a lot of my spare cycles recently. I think its way more important to an agile process than is made out. Sure the XP books talk about OAOO and refactoring, but somehow the sheer importance of quality code seems to get forgotten on a lot of agile projects. Agile processes target difficult projects and trust in the teams’ ability to respond to changes and adapt to fluid situations. If your code isn’t agile, it won’t matter a damn how flexible your process is. Ask yourself in how many places your codebase would have to change if you swapped out your persistence layer. I’m not just talking about changing DB vendor, how about switching to flat files, or XML, or Prevayler. How many packages, classes, methods would be affected? How many tacit assumptions are in the code about how other bits of it work? Having agile code should mean that huge chunks could be replaced without having to touch the rest of it.

XP talks about discipline. An agile codebase must be far more disciplined than a non-agile one. It has to be able to change in unforseen directions as the project demands. This requires a level of quality that is frequently underestimated.

Inheritance Sucks!

Not really, of course, its just very easy to misuse, and used way too much. I’m talking about object inheritance (‘extends‘) here. Object inheritance should only be used to override behaviour, not state. If the only reason a class extends another is to get all its fields, that’s the wrong thing to do. That’s what object composition is for. If you want a one to one mapping to another class, include it as a field and add delegators for its public methods to your interface. In IntelliJ there’s even a menu option for it. What about polymorphism you cry? Thats what interface inheritance is for. If you need to be able to polymorphically pass your composed object to methods that expect your contained object, implement a common interface and make your methods accept that instead. Your code will be cleaner, more modular and (most importantly) less coupled. The title of this post should probably have been ‘Coupling Sucks’. Extending a class binds you to it far more tightly than wrapping it as a field. And working through interfaces makes testing a snap. Just plug your testcase in, or a full-fledged mockobject, although I rarely need a full Mock when I can just write MyTestCase extends TestCase implements Foo, Bar, Baz {...} and make the assertions directly based on which methods were called and in what sequence.

Most code uses inheritance more often than object composition, and much of the time composition would have been the better option. I suspect the reason is as prosaic as the fact that object composition involves more typing. This is no longer the case with IDE’s like IDEA.