Skip to content
Announcement

LLM-Generated Tests Are Everywhere — Most Are Useless

AI-generated tests are flooding codebases but catching fewer bugs. Here's what teams actually doing it well have figured out about LLM-generated tests.

April 13, 2026TechMeetups.io10 min read
LLM-Generated Tests Are Everywhere — Most Are Useless

The Test Coverage Number Went Up. The Bug Count Didn't Go Down.

Something strange has been happening across codebases in 2026. Test coverage metrics are climbing — sometimes dramatically — while production incident rates stay flat or even creep upward. If you've been paying attention to how teams use LLM-generated tests, the explanation is obvious: most AI-generated tests are theater.

They pass. They inflate coverage numbers. They make CI pipelines green. And they catch almost nothing, because they're optimized for the wrong thing.

I've spent the last two months talking to engineering leads at companies ranging from 15-person startups to large enterprises, attending meetups in Denver, Austin, and SF, and digging into how teams actually use AI tooling in their test workflows. The pattern is consistent: teams that let LLMs generate tests with minimal guidance end up worse off than teams that write fewer tests by hand. But the teams that have figured out how to use LLMs for testing — they're genuinely shipping faster and with fewer regressions.

Here's what separates the two groups.

The Core Problem: LLMs Test the Implementation, Not the Behavior

When you ask an LLM to "write tests for this function," it does something predictable: it reads the implementation, figures out what the code does, and writes tests that verify the code does exactly that. This is tautological testing. You're paying compute to confirm that the code you wrote does what you wrote.

These tests have a few telltale characteristics:

  • They mirror internal structure. If the function has three branches, the LLM generates three tests — one per branch — with inputs carefully chosen to hit each path. This feels thorough. It is not.
  • They assert on implementation details. The tests check that specific internal methods were called, that data was shaped in a particular intermediate way, or that a particular execution order was followed. Refactoring becomes impossible without rewriting tests.
  • They miss the edges that matter. Because the LLM is reading what the code handles, it doesn't generate cases for what the code doesn't handle. The missing `null` check, the race condition, the off-by-one — these are invisible to an approach that treats existing code as the spec.
  • They're verbose. A generated test file is often 3-5x longer than a hand-written equivalent, with repetitive setup and marginal assertions that create maintenance burden without proportional value.

The result: a test suite that looks impressive in a coverage report but acts as a change detector rather than a regression catcher. Every refactor breaks dozens of tests — not because behavior changed, but because the tests were coupled to implementation details.

What's Actually Working: Behavior-First Prompting

The teams getting real value from LLM-assisted testing have converged on a workflow that's counterintuitive: they spend more time on the prompt than they would have spent writing the test. Not because the prompts are complex, but because the upfront thinking about what to test — as opposed to how to test — is the actual work.

Here's the pattern that keeps showing up:

1. Write the spec, generate the test

Instead of pointing an LLM at code and saying "test this," effective teams write a short behavioral spec first — sometimes just 3-5 bullet points describing what the function should do from a consumer's perspective — and ask the LLM to generate tests from that.

The difference is subtle but massive. A spec-driven prompt produces tests that:

  • Treat the function as a black box
  • Assert on outputs and side effects, not internal state
  • Survive refactoring because they're coupled to the contract, not the implementation
  • Sometimes catch bugs immediately, because the spec describes intended behavior that the code doesn't actually deliver

One engineering lead I spoke with at a Denver meetup described it as "TDD with an AI ghostwriter." You still do the hard thinking about what correctness means. The LLM does the boilerplate.

2. Use LLMs for edge case generation, not happy path

This is the highest-leverage application, and most teams are underusing it. If you already have a working happy-path test, you can feed it to an LLM and ask: "What edge cases are missing? Generate tests for inputs that might break this function."

LLMs are surprisingly good at this because it's essentially a creative divergent-thinking task — and modern models excel at generating variations. Teams report that LLM-suggested edge cases catch real bugs roughly 10-20% of the time, which is a dramatically better hit rate than happy-path test generation.

The trick is specificity. "Generate edge cases" produces noise. "Generate edge cases involving empty collections, concurrent access, unicode in string fields, and timezone boundaries" produces tests you'd actually want.

3. Generate property-based tests, not example-based

This one surprised me. Multiple teams have found that LLMs are better at writing property-based tests (using frameworks like Hypothesis, fast-check, or QuickCheck) than example-based unit tests. The reason makes sense once you think about it: property-based tests describe invariants ("the output should always be sorted," "serializing then deserializing should return the original"), which are behavioral by nature. The LLM doesn't need to invent specific examples — it needs to articulate properties, and then the framework does the exploration.

Teams using this approach consistently report finding more bugs per test written than any other method.

The Workflow Shift: Review Tests Harder Than Code

Here's a cultural change that's quietly spreading: teams that use LLM-generated tests are shifting code review emphasis. Instead of spending most review time on the implementation and glancing at tests, they're doing the opposite.

The logic: if an LLM generated the test, a human didn't deeply reason about what it's checking. The review is where that reasoning happens. Reviewers ask:

  • Does this test actually verify the requirement, or just the current behavior?
  • If I introduced a subtle bug, would this test catch it? (Some teams call this the "mutation test" thought experiment during review.)
  • Is this test going to break the next time someone refactors?
  • Is the setup so complex that nobody will understand what's being tested in six months?

This is a meaningful inversion. Tests used to be the part of a PR that got rubber-stamped. Now they're the primary review surface. If you're a team lead and you take one thing from this article, consider implementing this: make AI-generated tests the highest-scrutiny part of code review.

What to Stop Doing

Let me be blunt about practices that are actively making codebases worse:

PracticeWhy It's Harmful
"Generate tests for 100% coverage" as a promptProduces tests that exist to satisfy metrics, not catch bugs. You get maximum maintenance cost with minimal signal.
Auto-generating tests in CI without human reviewCreates a growing body of tests nobody understands, which teams eventually start ignoring or deleting wholesale.
Using LLM tests as the sole test suiteNo human has reasoned about correctness. You've outsourced your understanding of your own system.
Generating integration/E2E tests with LLMsThe failure modes are too complex and environment-dependent. LLMs hallucinate setup steps and make incorrect assumptions about system state.

Notice a theme: the failure mode isn't that LLMs write bad syntax or tests that don't compile. The models are past that. The failure mode is that the tests are conceptually wrong — they test the wrong thing, or they test the right thing at the wrong level of abstraction.

Concrete Takeaways You Can Apply This Week

Takeaway 1: Adopt the "spec-first" generation pattern. Before generating any test, write 3-5 bullet points describing what the function/module should do from a consumer's perspective. Feed that to your LLM, not the source code. If you must reference source code, include it as secondary context with an explicit instruction: "Test the behavior described above, not the implementation details in the code."

Takeaway 2: Run mutation testing on your LLM-generated tests. Tools like mutmut (Python), Stryker (JavaScript/TypeScript), and pitest (Java) will tell you what percentage of introduced mutations your test suite catches. Most teams find that hand-written test suites catch 60-70% of mutations, while naive LLM-generated suites catch 30-40%. That gap is your measure of test quality. Run it monthly and track the trend.

Where This Is Heading

The interesting teams aren't using LLMs to write tests — they're using LLMs to reason about testability. Feed a module to an LLM and ask: "What makes this hard to test? What would need to change to make it easier?" The answers are often architecturally insightful — suggesting dependency injection points, identifying hidden coupling, recommending interface boundaries.

This is a more profound use than test generation. It's using AI as a design review tool that happens to express its feedback in terms of testability. And testability, as anyone who's practiced TDD seriously knows, is a proxy for good design.

I expect that by end of year, the leading AI coding tools will shift their testing features from "generate tests for this file" to "analyze this module's testability and suggest improvements." The teams already doing this manually are seeing real architectural benefits.

If you're attending meetups or conferences this spring — and there are excellent ones happening across most major metros right now if you explore tech events in your city — testing practices are one of the most productive discussion topics. The gap between how teams think they should use AI for testing and how teams actually getting results use it is wide, and it closes fastest through conversation.

FAQ

Should we stop using LLMs for test generation entirely?

No. LLMs are genuinely useful for generating test boilerplate, edge case suggestions, and property-based tests. The problem is using them as a hands-off "generate all tests" button. Treat them as a drafting tool where a human provides the intent and reviews the output critically, not as a replacement for thinking about what correctness means.

How do we measure whether our LLM-generated tests are actually useful?

Mutation testing is the most direct measure. Run a mutation testing tool on your suite and look at the mutation kill rate. If your coverage is 90% but your mutation kill rate is 35%, your tests aren't catching bugs — they're just executing code. A healthy suite kills 60%+ of mutations. Track this metric over time alongside your coverage number.

Are there types of tests where LLMs work better than others?

Yes. LLMs are strongest at unit-level tests for pure functions, property-based tests, and edge case generation for well-defined interfaces. They're weakest at integration tests, E2E tests, and anything requiring reasoning about system state, concurrency, or environment-specific behavior. Use them where they're strong and write the rest by hand.

Find Your Community

The best way to level up your testing practices is to talk to engineers who are figuring this out in real time. Local dev meetups are where these conversations happen — not polished conference talks, but honest "here's what actually worked and what didn't" discussions. Find developer meetups near you, check out what's happening in your area on the events page, or browse engineering roles at teams that take quality seriously.

industry-newsnationalengineeringtestingAI toolingdeveloper experiencecode qualitysoftware engineering

Discover Denver Tech Communities

Browse active meetups and upcoming events