One of the most common questions about testing, including what to write tests for, is what NOT to write tests for.
When people ask me what to write tests for, my honest but maybe not very helpful answer is “basically everything”. But I don’t test literally absolutely everything. There are some cases when I choose to skip tests.
My criteria for skipping a test
My habit of writing tests for everything leads me to write tests for my code by default. For most of the code I write, I actually finder it harder to write the code without tests than with tests.
But sometimes I get lazy or my instincts tell me that a test would be a waste of time. When I’m feeling like this, I ask myself three questions:
- If this code were to misbehave, would it fail silently?
- If this code were to misbehave, how bad would the consequences be?
- If this code were to misbehave, how frequently would it fail?
- How costly would it be to write a test?
If the code I’m working on would fail in a very obvious way, and the consequences are minor, and the failure would only happen once a year, and the test would be very costly to write, then that’s a case where I would probably skip the test.
On the other hand, if the code would fail silently, OR if the consequences would be bad, OR if the failure would be frequent, OR if it’s super easy to write the test, then I would just write the test.
You could think of these questions as a boolean expression where all the items get OR’d together:
“Should I write a test?” formula (boolean OR)
- Might fail silently?
- Consequences might be bad?
- Might fail frequently?
- Test is easy to write?
If any one of the items is true, then the whole boolean expression is true and I go ahead and write the test. Otherwise I skip the test without guilt or worry.
Behavior vs. implementation
There are also entire types of tests I avoid.
I don’t test for things like the presence of associations, the presence of methods, etc. Such tests are pointless. Rather, I test the behavior that these things enable. Testing the behavior is the only way you can really be sure anything works.
- I’ll skip a test if and only if the feature won’t fail silently, the consequences won’t be bad, the failure won’t occur frequently, and the test is expensive to write.
- I don’t test implementation details, but rather I test the behaviors that the implementations enable.