Fearless Refactoring

January 1, 2012 on 10:52 am | In Programming | No Comments

I was going to title this Unit Testing, but then I realized that would be giving the wrong emphasis, because unit testing is only useful when refactoring or enhancing.

If you build a system that will never change after it is deployed, then of course manual testing is sufficient, because there is no point in automating something that you will never do a second time. However, every programmer reading this is now either laughing or shaking their head, because software never stops changing, so automated testing is a huge time saver.

Unfortunately, I see many unit testing practices that actually hinder modifications to software. Test classes for Java beans are the worst, since testing getters and setters doesn’t add any value at all, but any unit tests for internal implementation details hinder refactoring.

The ideal unit tests validate the API that is exposed by a subsystem. This allows the internals to be refactored or even completely re-implemented without modifications to the tests. For example, a REST service can be tested by validating the output of each url for various valid and invalid inputs. Similarly for graph algorithms, data compression, image processing, etc., which are implemented as deep libraries with tiny public API’s. (This is only one of many reasons to keep the API of any library as small as possible.)

I do agree that separate tests for internal API’s can be useful for isolating an error in a complex subsystem, but these should be used sparingly, because the testing code may have to be thrown out during a major refactoring. (A better solution is often to split a large, complex subsystem into smaller, reusable components.)

Excessive need for mocks is a big red flag. It can be helpful to mock an http request/response pair or a database connection, but if I have to mock a large fraction of the Struts2 framework to test five lines of my code, and then Struts2 changes so my mocks no longer emulate the actual framework behavior, then the test is worse than useless. It is misleading.

So the next time you sit down to write tests, ask yourself whether the tests will help or hinder your next major refactoring effort.

Thanks to Tim Bray’s article for the kick.

Notes

Some argue that one should not even mock database connections. When building a framework that has plugin points, it is better to build sample plugins rather than use mocks.

UI’s pose a different set of problems, because automation requires emulating user actions, which is significantly more cumbersome than mocking input data. I prefer to test UI’s manually for two reasons. First, forcing myself to repeatedly use the interface helps me identify the annoying parts, so I can improve them. Second, for web applications, a critical part of validation is checking that everything looks right, and I don’t know of any way to automate this.

No Comments yet »

RSS feed for comments on this post. TrackBack URI

Leave a comment

You must be logged in to post a comment.

Blogroll

Powered by WordPress with Pool theme design by Borja Fernandez.
Entries and comments feeds. Valid XHTML and CSS. ^Top^