What should, and shouldn't, be covered by unit tests?

Viewed 4845

Clearly, I don't understand unit testing. This is fine, considering I've never done it before. I'm starting a new project, and wanted to bake unit testing into it from the beginning, so I'm looking to learn.

I had always equated unit testing with code coverage, thinking that you should have unit tests which cover every function/method in your application, but clearly this isn't the case and I've completely misunderstood the concept.

So,

  • What sorts of functions benefit from unit testing?
  • What sorts of functions shouldn't be unit tested?
4 Answers

I had always equated unit testing with code coverage

That is not entirely wrong. Unit tests / any other sort of test automation have only one truly undeniable benefit that holds in 100% of cases: they actually run the code i.e. they cover it. Compiler doesn't run the code. Static code analysis doesn't run the code. Obviously reading the code won't make it run. Automated tests do run the code (as well as manual debugging).

Any other claimed benefits are only potential and fully depend on competence and best intentions of those who write tests.

thinking that you should have unit tests which cover every function/method in your application, but clearly this isn't the case

Correct, not every single line of code is worthwhile to be automated to run during build.

So,

  • What sorts of functions benefit from unit testing?
  • What sorts of functions shouldn't be unit tested?

With above in mind, at least two conditions should hold:

  • possibility of error can't be eliminated statically (try to design code the way that makes invalid states and scenarios impossible to represent and save yourself from heaps of unit tests)

  • possibility of error is not low, e.g. code is not trivial / very cohesive etc.

OR

this is a mission-critical component / deploying an error has dire consequences. In this case it's worth to be a paranoid, even if possibility of error is extremely low.

OR

Code is a part of published / externally visible contract e.g. a library interface. In that case even primitive tautological tests are useful as they act as executable requirements / protect you against unintentional changes of published contracts (sort of specific case of a previous bucket of mission-critical tests).

OR

Writing a test is actually easier than reaching this code manually, can be well true in large monolithic behemoths. It doesn't mean you have to keep the test around forever, feel free to delete it later if it incurs large maintenance costs. But code must be run and results must be observed and accepted at least once before deployment, of course.

Above is true as of my best current knowledge provided that one's priority is to be pragmatic. If priority is to have good excuses for sloppy job then aim for 100% coverage and other religious test practices are perfectly justified (think "it's not my fault - all tests were green!")

Related