惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
J
Java Code Geeks
U
Unit 42
GbyAI
GbyAI
大猫的无限游戏
大猫的无限游戏
L
LangChain Blog
D
Docker
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
罗磊的独立博客
I
InfoQ
The Cloudflare Blog
小众软件
小众软件
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
S
SegmentFault 最新的问题
爱范儿
爱范儿
Hugging Face - Blog
Hugging Face - Blog
P
Proofpoint News Feed
V
V2EX
月光博客
月光博客
Martin Fowler
Martin Fowler

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Your AI Writes Tests That Can Never Fail
Odilon HUGONNOT · 2026-06-28 · via DEV Community

Odilon HUGONNOT

You ask the AI for tests. It hands you twelve, all green. CI passes. You merge. Three days later a bug ships, on a function those tests were supposed to cover. You reopen the test file and it clicks: it ran, it passed, and it tested nothing.

A green test isn't a proof. It's a hypothesis. And an AI, left to its own devices, is very good at writing hypotheses that can never be disproved.

The phantom test

Take a dead-simple function, a discount above 100 euros:

func Discount(total int) int {
    if total > 100 {
        return total - 10
    }
    return total
}

Here's the kind of test an AI produces when you ask "write me a test for this" with no further framing:

func TestDiscount(t *testing.T) {
    got := Discount(150)
    if got < 0 {
        t.Errorf("result should not be negative")
    }
}

This test is green. It does run the discount branch (so your coverage climbs). But look at the assertion: got < 0 is never true, whatever Discount does. Replace total - 10 with total + 10, with total * 2, with 42: the test stays green. It doesn't check behavior, it checks that the lights are on.

Coverage doesn't measure what you think

The trap is that this phantom test inflates your coverage. Coverage counts lines executed, not assertions that bite. A line crossed by a test that asserts nothing useful counts as much as a line genuinely verified. So a 90% coverage report can hide half a suite of tests that will never fall, even if you break the code on purpose.

That's exactly an LLM's playground. Its reward signal is "the tests pass". Not "the tests catch a bug". With no external oracle to stop it, it drifts toward the shortest path to green: soft assertions, mocks that test themselves, cases that never exercise the risky branch.

The red-check: break the code, demand the red

The counter is one move, and it's as old as TDD: before trusting a test, check that it knows how to fail. Mutate the line it's meant to protect, rerun, and expect to see it go red. If it stays green, it's vacant.

On our function, I change the discount for one second:

// temporary mutation: - becomes +
return total + 10

The phantom test stays green. Verdict: bin it. Here's the one that earns your trust:

func TestDiscount(t *testing.T) {
    if got := Discount(150); got != 140 {
        t.Errorf("Discount(150) = %d, want 140", got)
    }
}

With the same mutation, Discount(150) returns 160, the test goes red instantly. It bites. That's a test: not one that passes, one that knows why it might not.

Automating the red-check: mutation testing

Doing this by hand on every test doesn't scale. That's precisely what mutation testing automates: the tool applies hundreds of small mutations to your code (a > that becomes >=, a + that becomes -, a gutted return) and reruns your suite after each one. Every mutation that makes no test go red is a surviving mutant: a hole your tests can't see.

In Go, gremlins does the job:

go install github.com/go-gremlins/gremlins/cmd/gremlins@latest
gremlins unleash ./...

It gives you a mutation score: the percentage of mutants killed. Where coverage tells you "this line is crossed", the mutation score tells you "this line is actually tested". The two numbers have nothing to do with each other, and it's the second that counts.

How I wire it into an AI loop

When I let an agent write code and its tests, I don't let it declare itself done. Before any review, an objective gate runs: build, lint, test suite, then a red-check on the critical tests. The agent mutates the target line itself, checks the test goes red, restores it. A test still green after mutation gets rewritten, not negotiated. The LLM doesn't get a vote on "does this actually test something": the mutation decides, it only observes.

The rule that falls out is simple: no generated test enters the suite without proving it can fail. The cost is tiny, the payoff huge, because a vacant test is worse than no test. The absence, you see it. The vacant one lulls you.

Conclusion

We've learned to distrust AI-written code, so we review it. We still extend blind trust to the tests it writes, because they're green. But green doesn't prove itself: a test is only worth the red it's able to produce. Until you've watched a test fail at least once, you don't have a test, you have a decoration.