fun mCullenMcClellan(thoughts: List<Thought>?, work: List<Work>)

Test Driven Development: What it is and what it isn't

08-16-2022

Test Driven Developement, or TDD, is a highly debated developement practice. Some engineers will say that it is pointless, product managers will tell you that it slows you down, and many advocates of the practice will say it is the only way to code. Sadly, I believe that most people in the industry don’t know what TDD is exactly, even many of those who attempt to practice it. I, for one, was one of them. I firmly believed that I understood what TDD, wrote my test first, and almost always ensured that I have an extremely high code coverage, but I have come to understand that Test Driven Development has very little to do with all of that. In fact, it’s really not about the tests at all. It’s about the behavior.

If you’ve never heard of TDD before, it can be loosely defined by Martin Fowler as “a technique for building software that guides software development by writing tests.” Kent Beck gets credit for developing the practice in late 90s, during the same time period that the Agile Manifesto was signed. The process goes like this: you have requirement that you need to implement in your codebase, you write a test that will pass if the requirement is fulfilled but will fail currently, then you implement the bare minimum for that test to pass, and then you repeat this process until all of the requirements have been implemented. The idea is that when you do this you can make changes to the code’s structure without changing its behavior, also known as refactoring, with confidents because your test will fail if you changed something you shouldn’t, with the end promise being that your codebase will be easier to maintain and your software will be of higher quality. I use this process every day at work and I find it to be really helpful pactice. I believe it does make the code I write more concise and makes it easier to solve complex problems. However, TDD can and does get abused, and that abuse it’s part of what gives it a bad rap.

When I first started practicing TDD, I wrote test for everything. Making a new class? Well that class needs a test for it’s constructor. Writing a method deep within the application that joins a few strings? Definitely writing a test for that. Logging something to the console? You guessed it, wrote a test for it first. By the time I had completed a story, I would had 500+ lines of test code for 50 lines of implementation. I thought this was the right thing to do, but as soon as anyone, including myself, tried to refactor my code my test broke. I didn’t think anything of it at first. I just thought it was part of the process. That is until I watched talk given by Ian Cooper at DevTernity Conference.

In this talk, Cooper shared a lot of the same experiences I had with TDD. In his talk, he mentions the excessive amount of tests in comparison to the implementation and tests that mocked the whole software system away, both of which I had experienced the rigid nature of this in the wild. He argued that these are actually problems and caused by a poor execution of TDD and goes on to say that what we should really be testing is the outer most behavior, not the implementation details and I tend to agree.

In practice, this is far more aligned with the idea of TDD that I described earlier. The business requirement has an underlying expected behavior and the test that we write to should test the cases of this behavior. Doing it this way does allow you to change the implementation details without diving into 15 different test files to fix the parameters to a mock. My development practices were tending more toward this to a degree, but truthfully this talk resonated with me and definitely marked a turning point in how I practice TDD. Not only will you write the most valuable test possible that actually lead you towards achieving your requirement’s goal, but it will also save time, making the project manager happy, allows TDD to be undisruptive to and more appealing to other developers, and brings the whole process of creating software closer to the end user that the requirement was (hopefully) written for.

References:

https://martinfowler.com/bliki/TestDrivenDevelopment.htmlYouTube: TDD, Where Did It All Go Wrong (Ian Cooper)