2025 Public Training Schedule
January 14 – 17, 2025 – Agile Analysis and Design Patterns – Half-Day Sessions
(c) 2024 To Be Agile
Like most metrics in software development, code coverage can be a good indicator or it can be heavily abused.
I know many teams that have a code coverage standard. For example, 80% of their code must be covered by unit tests. The problem with having a standard for the percentage of code coverage is that not all code is straightforward to test and sometimes what happens is developers will write tests for the code that’s easy to cover, such as getters and setters, and leave complex computations that are harder to test uncovered.
I don’t believe in having a percentage of code coverage as a standard. I think that all code that we write should be covered by tests because I see unit tests that I write when I do TDD as a form of specifying the behavior of the system. My tests are executable specifications and if that’s true then everything I would put in the spec should go in my tests. If my specification says that a name field has a getter and setter than I also want to have tests for that getter and setter, not because I’m concerned that this code needs tests but rather because I think about my tests as specifications.
I am very concerned with building practices that are shareable so that we can build consensus across our industry. Seeing unit tests as a form of specifications helps me get really clear on the number and kind of tests I need to write in order to elicit any behavior. I find this approach extremely valuable so I don’t mind taking it to its logical conclusion.
When doing TDD, if you always write the test first and always write implementation to make a failing test pass then by definition you will always have 100% code coverage. This is why I rarely use code coverage tools when I’m building code test first. However, I do use code coverage tools when I refactor my code to make sure that my code coverage doesn’t change. If, when I refactor my code, I see my coverage change then it tells me something is wrong. I either have dead code in my project or my tests are not doing what I think they’re doing.
I know that a lot of developers feel that writing tests for simple code like getters and setters are a waste of time, and if you feel that way then I’m not going to argue with you. As long as your getters and setters are simple and don’t contain any additional business rules then you really don’t have to write tests for them. However, I still do because, again, I see my tests as specifications and I like the consistency of having 100% code coverage. I even have unit tests for the constants in my system. I want to have tests for anything in my code that could change the behavior of the system.
While I don’t rely heavily on code coverage tools when writing new code, I tend to rely very heavily on them when I’m working with legacy code. One of the first things I want to do when working with legacy code is to get that code under test so I can refactor it safely. In these situations, code coverage tools can be immensely valuable for showing me areas of the code that are safe and areas that are unsafe for refactoring.
So, code coverage tools can be valuable and they have their place but they can also encourage developers to do the wrong thing. If you must have code coverage standards then insist that complex coding is always covered.
Previous Post: « Make Your Test Fail First
Next Post: Introducing TDD to Teams »