Scene: It’s midnight. We slowly pan over a sparsely filled library. We zoom in on a tense, frazzled Computer Science student. With a practiced hand, he fills his code with print statements and debugs his code for umpteenth time. He steps over and over lines of code, struggling to find the reason why his code silently fails.
He could write some tests, but what’s the point? They’re bound to be as flawed as his understanding of his code, right? Besides, it would take time he doesn’t have to write all those tests. Left to his devices, he struggles for another hour or so before realizing he had an off-by-one error on one of his giant “for” loops.
I’m sure I’m not the only one who’s been in this situation. Rather than deal with the extra work of writing tests, you just decide to wing it. It could save you time, but on the other hand, it could cost you some painful nights of debugging some unfortunately timed bugs. So what exactly are the pros and cons to testing your code?
Testing can take many forms, but rather than getting bogged down on every type of testing, I’ll just focus on Test Driven Development. Test Driven Development (TDD) is the process of writing a test before any actual code, and using that test to drive the behavior of the code that gets written. The test should initially fail, forcing the developer to write just enough code to make the test pass. By coding the bare minimum, you ensure you’re not complicating or over-engineering your code. Then, you refactor the code for style, clarity, optimization, etc., using the test to ensure the logic is sound. With that done, you start the whole process all over again.
I’m sure by now, some of you have already figured out some of the strengths and weaknesses of TDD, but don’t get too far ahead. I’ll give you all the details up next.
- The tests help guide your code. If you can write incremental tests that slowly add the functionality you need, you’re more likely to end up with simpler code. If you struggle to write a test, or the test starts becoming unwieldy, chances are the test is showing you the code you want to write is becoming too complex and it’s time to refactor into something a little more manageable.
- Tests give you a safety net. Assuming you’ve got decent test coverage around your code, you can refactor and clean up the code without constantly worrying about introducing bugs. If your tests still pass after your changes, chances are you’re in the clear. As an aside, you should always double-check your work just in case :).
- The “hard” part is already over. If you practice TDD, you don’t have to worry later on about getting test coverage around a monolithic code block, with all its branching logic and complexity. Ideally, TDD should prevent this situation in the first place, but either way the tests are already written. Speaking of which…
- Your code becomes more modular and simple. Building on the last point, if you can drive all your functionality in through tests, your code should become more modular. You should end up with smaller units or work, making your code more reusable, testable, and maintainable.
- Tests can improve design decisions. Forcing yourself to drive functionality through tests can help you understand code architecture. It helps guide you toward modular code, which in turn helps you map out the design of your application or new functionality. It’s hard to explain, but TDD can give you the developer version of a Spidey-sense.
- Free documentation. The tests themselves can act as documentation for what the code does and how it responds to different input. It also lets an inquiring developer know some of the types of cases to look out for when out the design debugging an application.
- The tests will never be perfect. No matter how hard you try, you might not test every edge case. This can create a time sink for any obsessive developer (like myself) who wants to cover every single edge case and write test after test. You have to learn where to draw the line. But even if you learn how to do this…
- Tests will cost you more time up front. The added cost of writing tests before actual development work can be expensive. The hope is that they save you time in the long run, preventing time-consuming bugs and undecipherable code. It’s like an smoke alarm: if all goes well you might not ever need it, but if something comes up, it’s nice to have an early warning system.
- Limitations in understanding lead to testing holes. If the developer that writes the code doesn’t have a complete understanding of what code should do, it’s possible for the tests to reflect that. Test might not catch the bugs they weren’t designed to catch.
- TDD can lead to a false sense of security. Test created by TDD usually don’t test an application end-to-end. As I mentioned above, there is always the potential for bugs, and bugs that exist between the layers of your application are easy bugs to miss.
- There is an implied upkeep for tests. As code and functionality changes, the tests will need to change with it. This will increase the time and effort associated with any modifications to existing code.
I tend to believe despite all the cons, TDD improves your code and potentially improves you as a developer. But, I’ll leave the judgement to you. Do you think it’s worth it?