I was recently working on an application at work which was stable but had no automated test coverage. As it got bigger, I grew more worried about the fact that I couldn’t keep the entire code base in my head anymore.
As an app gets larger, it becomes harder to store a mental model of it in your mind. As a result, you aren’t really sure if changing one part of the app affects another.
I knew I had to write tests, but I wasn’t sure where to start. After all, this wasn’t some new app; it had tens of thousands of lines of code.
So after some brainstorming, I came up with a game plan that I’ll share with you.
The “What to test” Testing Framework
- Nominate a few areas (no more than 3 or 4) of the application which are important but untested.
- Write tests for these areas.
- Write tests for any new features that you develop.
Why does this framework work?
Going from no code coverage to a high percentage is intimidating. There are so many tests to write! Instead, take advantage of the fact that not all parts of a codebase are equally important. There are mission-critical components, and then there are supporting components. This framework ensures that:
- The most critical parts of your application are tested first.
- As you make progress, you are able to subsequently cover less important parts of your application.
- By writing tests for all new code you write, you are able to get yourself into the habit of writing tests.
- As you write tests, you see your coverage numbers go up, which incentivizes you to keep going.
What about Test Driven Development?
Many people preach Test Driven Development, but in a startup environment, it is not always practical to adhere to it because it does slow down development.
If you do not have the engineering resources to practice TDD, I believe the next best thing is the method that I mention above.
Choosing the right type of test
There are many different types of tests: unit, functional, integration, performance, etc. I recommend writing unit tests first because they are usually:
- The least fragile
- The fastest to write
- The fastest to test
Unit tests let you quickly boost code coverage. After you write a decent amount of unit tests, move on to writing a few integration tests.
What to do after writing the tests
Tests are pointless unless you are constantly able to view their state. It’s imperative to be able to the following on every commit:
- Which tests passed and failed?
- Which parts of your code were covered?
This is one of the primary reasons why I prefer writing tests using Jest, a testing library from Facebook. They have built-in code coverage reporting via Istanbul, which is extremely useful. Without it, there’s no way to ensure that the important parts of your code are covered.
I’ll be writing a tutorial on writing tests with Jest shortly, so make sure to subscribe to be notified about that.
Sign up to my newsletter to be notified about my next post. I only send emails when I write something new, and it’s usually weekly.
For those who like Mocha, you can use Istanbul with it as well, but you just need to configure it yourselves. Here’s a guide about how to do that.
Once you have the testing framework set up, you can easily run it automatically in a number of ways:
- Run it as part of a CI pipeline. If you use GitHub, look into Travis. If you use Gitlab, look into Gitlab CI.
- Run it as a pre-commit hook. Here’s a great post by Ben McCormick that goes into this more.
Don’t forget to do this or your tests will get stale. When I initially set this up, it was a little demotivating because my code coverage numbers were around 10%. However, the constant visibility forced me to improve them.
Remove unused code
One overlooked way to improve your code coverage numbers is to remove old code is no longer being run. Don’t be scared to delete it! If you ever need to refer to it later, use git.
You can drill into each file to see what code is being executed.
Start writing tests, remove old code, and use the framework to ensure that even if you don’t have high code coverage, you cover the important parts of your app. Good luck!