Andrew Lombardi published "Unit tests are not the enemy", a response to a run of posts on X in which developers announce they have deleted their unit tests, sometimes hundreds of thousands of lines of them, on the grounds that agent-written tests lock in slop, slow the agents down, and burn tokens. One cited benchmark found that removing tests cut agent time by six percent and spend by nine.
His answer is that the tests did not get bad on their own. They got merged without anyone reading them, and a test nobody read is a test nobody owns and nobody actually cares about.
The remedy he proposes is reading, with a short checklist for what to look for:
- Break the code on purpose and see whether anything fails
- Prefer tests that assert behavior over tests that narrate implementation
- Distrust a suite where everything interesting is mocked1
- Treat an agent editing a failing test as a red flag
- Point a second model, not the one that wrote the code, at the tests specifically.
He closes on economics: today's model pricing is subsidized, it will not stay where it is, and tests are how the organization keeps the understanding of its own product rather than renting it.
It's all great advice - that predates the current plague of AI agents! Tests that restate the implementation, that mock the thing under test, that go green while the behavior is wrong... all of these are a known failure mode of human-written suites, and this has been the case long before anyone prompted a suite into existence.
What the agents changed is volume and provenance. A person who writes forty tests in an afternoon has at least read them once. An agent that writes a hundred has not, and neither has the person who asked for them unless they choose to. The people deleting tests are reacting to something real - they are just burning the house down to get rid of it.
Two things worth adding for a JVM reader.
The first is that "break it on purpose" has been automated for fifteen years. PIT mutates the compiled bytecode, flips conditions, swaps return values, removes calls, and reruns the suite against each mutant. A mutant that survives is a failure for the suite - or an exposé of unnecessary code.
Running PIT against an agent-generated suite is the fastest way to find out how much of it is actually doing a verification of the codebase, and the surviving mutants are a better prompt for the next pass than any instruction in an AGENTS.md. It is slow on a large codebase, and it is not a substitute for a human reading the assertions, but it answers the question Andrew is asking at machine speed.
The second is that the all-end-to-end position he argues against is a pyramid inverted on purpose, and the people inverting it usually have a reason: their unit tests were coupled to structure, so every refactor broke them, so the only tests that survived a change were the ones that exercised the system from outside.
That is a complaint about how the unit tests were written, and the fix was always to write them against behavior. The end-to-end advocates and the unit-test advocates want the same property, a suite that fails when behavior changes and stays green when structure does. They disagree about where to get it, and the honest answer is both, in the usual proportions.
The economic argument is the piece's weakest leg, not because it is wrong but because it does not need to be right. If model pricing stays flat forever, a test suite that nobody reads is still a liability and a test suite that encodes intent is still an asset. The case for reading your tests stands on its own.
It's a well-done and probably timely article. If you're looking at your test suite and thinking, "do we really need it?" the answer is "yes," unless it wasn't serving its purpose in the first place. And if it wasn't serving its purpose, well... yes, delete it... and replace it with something that helps your code get better and stay better.
Andrew Lombardi and I are good friends in real life; he and I have written multiple books together, he designed the original UX for BCN because everything I came up with was awful, and he's an excellent person, despite being a [REDACTED, BE NICE IN PUBLIC]. Being good friends doesn't mean we don't hold each other's feet to the fire when we deserve it - in fact, being good friends demands we hold each other accountable. But I wholly agree with his points here.
-
Why you making fun of code, bro? ... oh, he's talking about Mockito and such, and he's right. I personally love that Mockito exists, but I use it only when I absolutely have to construct results artificially.
↩
No comments yet.
Sign in to comment