One of the first roles that I’ve been working on since I went full-time remote was that of the unit tester. I wasn’t used to being the QA guy before and although this was new to me, I’ve gotten the hang of it. However, as part of my role, I had to write the tests as well (PHPUnit). The other devs in my teams were not initially comfortable writing tests, or they were just more focused on releasing stuff.
Testing after the fact is pretty common
I am sure this doesn’t happen only to me. I’m sure there are countless other projects out there that follow the same process. Devs do the feature, someone does some QA, and then the task card is moved to the Unit Testing column. For anyone appreciating a TDD workflow, that’s just straight-out weird.
What is this Development Driven Testing thing weird? It’s weird because you lose so many of the benefits of writing tests alongside the features.
Testing after the fact is often unproductive
For starters, let’s say you found the feature to test to be very badly architected because of… deadlines. So bad that writing tests for it is either too difficult and non-productive, or the only way to do it is to refactor the whole thing. But the other dev has already delivered a refactored code, should you do it again? Or just skip the whole testing thing and release it, because, of deadlines?
Let’s say the code to be tested is well-written and can be worked with. By what metric? Most of the untested code that I’ve seen is controllers, services, and methods with hundreds of lines of code and very high complexity. Sure, it may look simple and well written for a programmer’s eye, but what does Phpmetrics have to say? Even if I, the tester, wrote a large feature without tests, I’d still produce the same suboptimal code that another programmer would call mehh 😂.
Not testing at all is the path to the dark side
The other way around with untested code, over-engineering, is also a problem. It’s easy to get distracted from a feature you’re building and start accounting for details and sub-features that weren’t requested and will probably never be used. It’s hard sometimes to just stay focused and build only what you need to build. It’s hard to know when to stop refactoring, but then again, it happens.
Ever worked on a legacy project? Why do all legacy projects have the same problems? How did they come to be like that? My biggest bet is that they grew with time, started making real money, and everyone was too afraid to mess around and “do things properly”. Why upgrade and groom a project if it’s working? If only there was a way to improve the project safely…
Hey, but doesn’t TDD take up a lot of time?
That’s another big misconception when it comes to writing tests alongside features. I’ve written tested code and I’ve written untested code and I can say with full confidence that tests haven’t cost me as much time as I anticipated they would. There are many cases when a testing environment helps me to write a feature faster. For example, when implementing a form with various inputs. I’m writing the inputs one by one and without tests, I have to check constantly with the browser to make sure that everything works. Otherwise, I don’t even have to leave the editor.
Oh, and it’s this other critical win when using tests. They change your way of thinking about problems, or rather, they help you uncover a sane path to dealing with them. The reason for this is that you are forced to think about use cases and implement them in sequential steps, which is very similar to the way machines process instructions. Eventually, you write code that follows this sequential thought process, steadily built with pieces that form a whole feature, and guess what, it will be very readable and easy to grasp by an outside observer, or future you.
TDD is your decision to make
I still think writing tests after the fact is here to stay. People who make decisions are not easily convinced by some software “theories”, right? They want hard facts and results. However, the decision on this is in your hands, fellow developer. You’re not going to change anything by asking for permission.
Funny enough, to prove this point even to myself, I got introduced to a modern Laravel project that had no tests, and I insisted that I would only accept the work if I was allowed to write tests. A few months in, we needed to do a major refactoring and upgrade to PHP 8.2. We did that, the tests were all green, and we were good to go. We all felt safe and protected and decided that every developer write their own tests, the benefits were obvious.
So give it a try at your projects. YOLO, don’t tell anybody. Just write some tests for your own tasks, let them hang in there, and grow them in size for some months, you’ll see the benefit in time. Your whole team will see.
TDD in the era of Copilot and ChatGPT
With the recent rise of ChatGPT and GitHub Copilot, the experience of writing tests has gone to another level. Once you get a bit comfortable with writing stuff by hand, an AI assistant will just blow your mind. Copilot is already generating so many of my tests these days, it barely takes minutes to write complex logic and assertions. I feel like these tools were made for TDD.
I thank you for reading this far and I hope you got some value for your time. I write about refactoring and testing from time to time. See you in the next post.