The Virtuous Cycle of Testing
There are many good reasons to write tests for your code: catching bugs, preventing functionality regressions, defining better interfaces to your modules, the list goes on.
But one reason isn't discussed quite as frequently that I like to call "the virtuous cycle of testing." Put simply, this virtuous cycle is the idea that writing more tests makes it easier to write other tests in the future.
I've seen it time and time again: everybody happily embraces tests until they get too hard to write. It's easy to write the test confirming that a banner component renders on a page; it's harder to write the test that confirms that the login flow and all of its error states are working properly. Similarly, testing interactions with external APIs is a common point for teams to draw the line of what they're willing to test since setting up a tool to mock responses can be daunting.
At a more abstract level, it's easy to write tests when you have a very similar bit of logic you can copy over and apply to the tests you need to write, but it's more challenging to write tests that explore a new domain and require extra setup and overhead. On top of that, if the new code being added isn't mission-critical, there may be a concious decision to not write tests at all.
And hey, I get it. Timelines force us into uncomfortable situations when it comes to delivering aspirational code. We can't write tests for every single use case in a system and that's ok. But that doesn't mean we should throw our hands in the air every time something is hard. A test suite that only covers easy-to-write use cases is better than nothing, but not much more.
Just as I've seen teams where a testing suite has dwindled over time, I've also seen teams who have a culture of excellence and go to the extra mile for testing even when it's difficult.
The most powerful mental model I've seen with having effective test coverage is to have the attitude "we should default to writing tests for new code unless there is a very good reason not to." Once that's in place, I've seen other pieces fall into place for how the team operates: engineers pointedly ask where the tests are during code review and offer to pair program when tests are missing.
Those are the codebases and teams I've enjoyed working in the most over the course of my career. The difference is palpable - from having fewer regressions in a system to making tests a normalized part of the development workflow. I suppose there's something to be said for the social dynamic as well in these cases - if everyone else is writing tests, I don't want to be "that guy" who just skips over them.
The next time you find yourself tempted to skip over a test because it's difficult, I would encourage you to not think of extra testing overhead as aspirational and instead think of it as an investment. Each time someone contributes a new test that covers one of those hard-to-trailblaze areas of code, it becomes a reference point that pays dividends for every developer on your team in the future. The more others can utilize these reference points, the more tests they'll write that will in turn help you in the future.
Test Automation, Release Engineering, CI/CT/CD Orchestration
12 个月Great read, Alex Lau! Thanks for sharing! As someone who has done a lot of testing, a lot of this resonates with me. You mention - "Timelines force us into uncomfortable situations when it comes to delivering aspirational code." So true. I've found in these types of situations, it sometimes helps to think of what you can still realistically deliver that would be the most "bang for your buck" in terms of testability. Ironically, this type of thinking exercise can still lead to times where you start to tackle the more difficult to automate problems, even if you just get that started and deliver it in the following sprint. The value add for the team overall (investment as you mentioned) really pays off. Just make sure to ask first, communication is key in this type of scenario.
Operating Partner @ Diversis Capital | Tech Exec
12 个月You mention a number of good reasons for writing tests (beyond the virtuous cycle of writing more tests). One thing I've observed is something I call "design for testability"--so writing code knowing you are going to write other code to test it affects how you design the code to be tested. I think in many cases it results in simpler code and more obvious (and therefore testable) branches and conditions. I see a parallel effect when teams adopt a strong demo culture--design for demoability. If you know you must demonstrate to your peers the work you've completed at the end of a sprint, it affects your approach to the functionality you built. Demoing is, after all, a form of testing.
VP of Global Sales @ Testlio // 6x Early Stage Sales & Culture Leader // 2 Exits // Sickle Cell Warrior
12 个月hey Alex Lau - we here at Testlio couldn't agree more!