Write tests to solve trust issues, not code coverage
Published on
-/- lines long
I was listening to episode 6 of The Standup(opens in new tab) about test-driven development (TDD) and was thinking about how I personally write tests. Well, I do it when it feel a need for it.
I had to refactor a content exporter plugin for our website recently and wanted to preserve the current behavior, while at the same time introducing abstractions that would allow me to extend it.
So if a have to refactor a hot piece of garbage written 2 years ago and it has to preserve its current behavior on prod, I wouldn't trust a single soul on this planet for this. Including myself. Even though I wrote the original code.
This is where a test is useful, especially since this exporter feature currently has none. So I took a JSON blob of content from prod and the resulting JSON output after the current export logic runs it through, then I put both in a test. Now no matter what I do, I know that I preserve the exact same behavior.
After I finished this, I asked myself "do I write more tests now", "do I test edge cases now"? The answer is no. The new abstractions fit perfectly and unlike the mess before, I trust them a lot more. So this single test is enough to give me the confidence that I have the expected behavior.
My goal is to preserve this exact output for this exact input. In fact, it would suck to have a bunch of tiny, isolated tests passing, but then have the real thing break on prod. So this is is why you just test the real thing from prod. If my intention is to preserve this concrete behavior, then this is what I should be testing, not some imaginary, hypothetical stuff.
But what if I run into some edge cases? Well, I'll fix them when they happen, if they happen. After all, this is internal code and I know the exact context it runs in really well. I also know the consequences of it not working. If it's open-source instead, and everyone under the sun can subject to all sorts of crap, well then my trust would go down a lot. And with the decreased trust, I'd want more tests.
What about code coverage, though? Well, it's just a metric. Low coverage can be used to provoke trust issues, but it shouldn't be the end-goal. The moment a metric turns into a goal, you start losing the point of it. The driving force should be the trust.
It makes no sense to write tests just for the sake of it. They don't affect the actual implementation; they just poke at it. So having a high coverage doesn't necessarily mean you have more stable code. You can have a perfectly functioning project without a single test. Tests solve a human issue, not a technical one, and using coverage to quantify it can be misleading, distracting, and annoying.
But how do you scale this "trust" at an organizational level? Not with some shitty coverage policy. On a larger scale, trust simply distributes to other people. If someone approved your PR and your code breaks, it means they trusted code they shouldn't have. This is their misjudgement. If they weren't 100% sure about your code, they should have wanted tests for the parts that seemed off.
So can you do TDD? Well, if you're using tests to solve trust issues you have with your own code as you're writing it, then yes. They're just a way to automate the checks you would otherwise have to do manually to verify that what you wrote is actually doing what you want it to. Once you reach a behavior you like, you "lock it down" with a test, to give yourself confidence that you won't lose it.
The goal is always to feel better about your code, therefore happier, and therefore more productive. If you feel like shit writing a test and you think it's pointless, don't do it. If you also think your code is shit and you don't trust it, then refactor it so it doesn't rub you the wrong way.
In any case, tests solve a subjective problem, so you should write them when it feels™ right, not because a number told you so. Otherwise you're distracting yourself from building actual shit.
So what I like to do is test-driven assurance. The goal is to just have confidence in the code you wrote (or the code you're reviewing) and tests are merely the means of giving and preserving that confidence across commits.