Tuesday, January 03, 2012

Code coverage - unintended benefit

Unit test coverage is not a panacea.  You can reach 100% unit test coverage without a single assertion about outputs or business logic, in which case the tests aren't that useful.

Or are they?  Just the act of executing every single line and branch of code does provide one important value: it demonstrates that you can show what inputs or conditions trigger which parts of the code.

More importantly, the act of getting there helps reveal sections of code and conditionals that you might not even need.  Having a coverage target also gives you incentives to stay "clean" and avoid gratuitous not-null checks or try/catch blocks, two pet peeves of mine.  (I've seen too many not-null checks that looked defensive at first but in reality just kicked the can down the road, further obscuring the real problem.)

The other benefit I've found is that a coverage goal encourages refactoring that you should be doing anyway, because well-factored code is easier to unit test.  For instance I had one JSF/JPA application where I was accessing JPA EntityManagers directly in the JSF managed beans.  This made unit tests on the managed beans annoying because I had to mock out EntityManager.createQuery and dozens of Query.setParameter calls for each JPA action.  By pulling the JPA actions into a separate DAO layer, I could just mock a single call to myDAO.getStuff(arguments).  Plus, after isolating the DAO, I could then write an integration test on the DAO hooking up to a real database.

Other related links:
http://www.wakaleo.com/blog/316-code-coverage-as-a-refactoring-tool
http://codebetter.com/patricksmacchia/2009/06/07/high-test-coverage-ratio-is-a-good-thing-anyway/

No comments: