A student recently asked me for some thoughts on how and where to write tests. In response, I tried to distill my answer down to the most basic principles of how I decide what to test, what not to test, and how to test, and it came down to two things. My goals in testing, fundamentally, are these:
If I refactor my code and my tests pass, I want to feel pretty confident that everything still works. I want to be able to trust my tests when they tell me everything is working.
When I decide to add functionality or change the behavior of my application, I want my tests to feel relatively easy to modify accordingly.
If I refactor some code and run all my tests, and they all pass, and I’m still afraid I might have broken ten different things, then something is wrong with how I’m testing. If this happens regularly, I’m going to start wondering why I’m testing at all. If my testing can’t make me feel confident in my code changes, what is it for?
If I decide to change how a piece of my app functions, stare at my code, and feel immediately exhausted contemplating how hard it will be to add to or modify the tests to reflect the new behavior, then something is wrong with how I’m testing. If this happens regularly, eventually I’m going to stop testing out of sheer frustrated exhaustion because I just want to get to writing the code, dammit!
My goal in deciding where and how to write tests is to hit a sweet spot that doesn’t hit either of the above issues. I try to write tests that make me feel confident and that aren’t exhausting to write. In some degree, these two principles feel oppositional. Writing fewer tests can be a good way to keep from feeling overwhelmed by test writing, but it’s also a good way to destroy your confidence in new code that passes your few tests. Writing more tests may make you more confident that you’re not breaking things, but it also means more work, and more likelihood test-writing will start to feel burdensome.
To some degree, they can be oppositional. But to some degree, also, the way you write your tests and the way you architect your app have a massive impact on how much you trust your tests and how hard they are to write. Getting this stuff right is just as much about how you test as how much you test.
I’m not writing this to tell you what to test and how. That is a hard problem that we all fail at all the time. I’m writing this because I think having guiding principles is important. Above all the technical speak about what to test and how, what we want out of tests is to be able to have confidence in our code without having to do so much work that it takes all the joy out of writing it.
Whether you’re new to programming, or have been doing it a long time, it’s worth keeping these first principles in mind. If you need to decide whether or not to write a particular test, or how to write it, ask yourself if that test will make you feel more confident in your application when it passes, and ask yourself if keeping it up-to-date is going to be so much work you’re not going to want to do it. If the answer to either of those questions isn’t the one you want, it’s worth doing some rethinking.