I recently ran Code Coverage analysis for an application I maintain and the results inspired me to write about it. Writing tests for applications is often a debated topic, but I don’t want to get into that debate. I’m assuming you’re reading this because you like the idea of testing but face defeat for one reason or another. I’d like to talk about how and why sometimes you need to just hunker down and get to it, no matter how futile it seems.

It often seems easier to skip writing tests when the application you inherit doesn’t have any testing setup, or worse, a lot of broken tests. Personally, I’m a big believer in the The Broken Window Theory. If things are so bad that you are afraid to test, I think that’s likely when it’s most important to get things in working order.

The Usual Atrocity

I took over this application in January 2017. This was a typical scenario where an application had been built in a modern framework (Laravel) using a lot of non-framework code, some of the provided console commands were broken, there were no tests at all, and worse yet, things blew up when I tried to get some very basic tests working (the default test provided with the framework was even broken). One thing I’ll always praise about Laravel is just how easy testing is. In my opinion it’s probably more than half the reason to use the framework. In all honesty, you almost have to try to break the provided default test case. Due to this frustration, I went against my better judgement and didn’t focus on cleaning this up as I had a QA person on the team.

Around the end of April / beginning of May, the QA person on my team was focused onto another project and wasn’t allocated any time for my application anymore. Even though I was told we didn’t have time to write tests, I decided I couldn’t go without them any longer. I spent 2 full days figuring out why things were broken and brought the application back to (nearly) the default testable state that Laravel usually comes in. I can now write HTTP/Endpoint tests and unit tests freely. I marked that as a considerable victory.

Knowing I wouldn’t get any sort of allowance to pause development and just go crazy writing tests, I made it a rule that any new feature was going to be 100% tested and any bugs that came up would get a test for the happy path, then a test that proves the bug is resolved. Progress was slow and daunting. Sometimes entire features would get sidelined which meant that the tests written for that branch didn’t get merged in. It felt even worse when sometimes we would contract work out and they would commit untested code, and a firm slap in the face when those commits would break what tests we did have. However, I couldn’t quit. I still have no QA on my team and providing quality work is too important to me.

The Verdict

At the end of October I decided to run the analysis and let the results sit, thinking I would run it again sometime in the future. I decided just before the New Year I should check again, if only to see how far we had come. I was shocked! We had a series of things go wrong in this 2 month time span, but we also had a lot go right.

Here are the results:

In 2 months we removed 277 lines of code, added 158 functions/methods, and added 21 classes. We increased our lines of code coverage by 11.57%, 10.69% for functions/methods, and 4.1% for classes. It felt like it took forever to get to 100 tests. Next thing I knew I was at 200 tests. We’re currently at 459 tests and 914 assertions.

Conclusion

It’s very important to me to have confidence in code. Not only does this allow me to deploy to production without worrying I blew something up, but it also allows me to refactor mercilessly until I’m happy with the quality of the code. The only way you can have such confidence is with tests.

The best time to start writing tests is when you start a new application. The next best time is today. Catching up on tests IS hard, but it absolutely CAN be done! Don’t give up!