Two types of assertions
Think of some conventional assertions you are familiar with:- They help you detect whether code is reachable. This can be very important! Imagine introducing a bug into your website that makes it impossible to complete the checkout flow, or a bug in your game that makes it impossible to win. Reachability of program states can be a vital correctness property.
- They help you to assess whether your tests are comprehensive and effective. If you’re sure that a sometimes assertion is reachable, and it’s reached in production, but your tests never trigger it, then that’s a sign that your testing is leaving important areas uncovered.
A generalization of code coverage
Coverage tools, which tell you which lines of code in your program are reached, are just a more restrictive kind of sometimes assertion. To be precise, they’re equivalent to addingassertSometimes(true) to every line of your program. Code coverage can be a good start to assessing the reachability of your code and the comprehensiveness of your tests, but it has two major weaknesses compared to the full power of sometimes assertions.
Weakness #1: Code coverage is not sensitive enough. All it tells you is that a particular location was reached. But it tells you nothing about, for instance, the values of variables in memory or the parameters a function was invoked with. Another way to put it is that code coverage only covers locations, while sometimes assertions cover situations.
Weakness #2: Code coverage is too sensitive. Not every line of code in your program is equal. In fact, the vast majority of it is probably unimportant — either it runs all the time, or it’s an unused part of some third-party library dependency and never runs at all. There are too many lines of code in your program for you to consider whether or not each one was covered. People respond to this deluge by computing coverage percentages, but these are a coarse tool that can hide information about whether particular vital locations were reached.
Sometimes assertions directly address both of these weaknesses. Instead of coverage merely informing you that a function was reached, you can instead check whether it was ever reached with a negative value passed for one of the parameters. And every sometimes assertion is placed deliberately, by a programmer. Whenever you hit (or don’t hit) a sometimes assertion, you know it was a situation that some human being at some point thought was important. Moreover, the overall number of them is small enough that you can look at individual examples if a code change or test change means that some are no longer hit.