On software testing

"write expressive tests that establish clear boundaries, run quickly & reliably, and only fail for useful reasons." -- Justin Searls
"I'm pretty convinced that the biggest single contributor to improved software in my lifetime wasn't object-orientation or higher-level languages or functional programming or strong typing or MVC or anything else: It was the rise of testing culture." -- Tim Bray

From undergrad and my first internships, automated testing has been an important part of my career as a software engineer. Much of my 6 years working at Google was devoted to improving test automation, and one of the things that attracted me to Very Good Ventures was their focus on testability in creating confidence and building excellent products.

In my continued learning, I went down quite a testing philosophy rabbit hole today. I started here and it led to lots of interesting views about unit vs integration tests, stub vs mock, coverage, TDD/BDD, etc. In addition to the two quotes above, here are a few key takeaways for me:

  • Naming differences (unit vs integration) are really murky (Martin Fowler). I think this can be especially true with Flutter widget, integration, and dart tests.
  • Front-end testing seems to be an especially difficult beast. Thorough code coverage creates confidence, especially as we modify existing software, but front end seems especially difficult to decide what granularity of unit or component to test. Higher-level tests verify overall behavior, provide lots of coverage, and allow refactoring lower-level details without changing tests. Lower-level tests are better for covering every tricky edge case, but they can make refactoring internal structure more costly because tests have to be updated. In my experience, end-to-end or visual tests are still frustratingly brittle and slow, but I do like the concept behind the "testing crab" of relying on higher level tests to exercise much of your code and adding more focused unit tests for the specific edge case behaviors you want to protect from being refactored away. (The Beyoncé Rule: “If you liked it, you should have put a CI test on it,”)
  • "Yes, you could use a public toilet and not wash your hands. Yes, you could eat spaghetti with your fingers. But responsible adults just don’t do those things. Nor do they ship untested code." -- Tim Bray
  • There isn't one ideology or approach that will fit every situation. Consider your goals, users, and team as you continue to find what works!

Follow up: I *really* like the way Rifat Ordulu talked about integration tests (for about 2 min) at 22:55 in his recent Fluttercon talk https://www.droidcon.com/2023/08/07/the-good-the-bad-and-the-ugly-side-of-selecting-flutter/ My understanding of what he said: Your goals will greatly inform which types of tests you should emphasize. - A small team that knows the codebase thoroughly, needs to move quickly, and mostly needs automated tests to ensure overall functionality before release may appropriately rely on a "diamond" or "crab" distribution with lots of integration tests. - If your objective (like Rifat's team's) is to enable many engineers to confidently make changes in a large codebase, a "pyramid" structure with more unit tests makes more sense.

Like
Reply

To view or add a comment, sign in

Others also viewed

Explore content categories