- BrainTools - https://www.braintools.ru -

Your AI Should Be Writing Tests. The Unfair Advantage Every Vibe Coder Ignores

A test is a note you leave for the computer. It says: “this thing works like this, and if it ever stops working like this, let me know.”

That’s it. Imagine you built a calculator. You write a note that says “2 + 3 must equal 5.” The computer checks this note every time something changes. If your calculator suddenly returns 6, the note fires. You don’t need to understand how the calculator works internally. You just know it’s broken because 2 + 3 is not 6.

This is the entire concept.

What a test looks like in practice

Before any code, here’s the plain-English version:

I have a function called calculatePrice. I give it an item that costs $10 and a quantity of 3. I expect $30 back. If I get anything else, something is wrong.

In Go, that becomes:

func TestCalculatePrice(t *testing.T) {
    got := calculatePrice(10, 3)
    if got != 30 {
        t.Errorf("expected 30, got %d", got)
    }
}
Your AI Should Be Writing Tests. The Unfair Advantage Every Vibe Coder Ignores - 1 [1]

Seven lines. The machine runs this, checks the result, and tells you if it’s wrong. You can have hundreds of these notes scattered across your project. They run in seconds.

That’s a unit test. “Unit” because it tests one small unit of behavior. Not the whole app. Not the database. Just: does this function do the one thing it’s supposed to.

Why this matters if you vibe code

Here’s the scenario. You’re building an online store. It has a price calculation function. It works. Users are buying things. Life is good.

You open ChatGPT or Claude and say: “Add a 10% discount for orders over $100.”

The AI gives you 40 lines of code. It looks right. The discount logic is there. You paste it in, try a $150 order, see a $135 total. Ship it.

What you didn’t notice: the AI rewrote calculatePrice to handle the discount, and in the process it changed how tax is applied. Orders under $100 now have tax calculated twice. Your $10 item costs $10.80 instead of $10.50. Nobody tells you this because you’re not going to manually test every old scenario after every change.

A test would have caught it instantly:

--- FAIL: TestCalculatePrice
    expected 1050 (cents), got 1080
Your AI Should Be Writing Tests. The Unfair Advantage Every Vibe Coder Ignores - 2 [1]

This is not a hypothetical. Large language models hallucinate. They confidently produce code that compiles, looks reasonable, and is subtly wrong. They’ll rename a variable and forget to update one reference. They’ll change what a function gives back and break something three files away. They’ll “simplify” a condition and break a rare scenario. The confidence is the dangerous part. The code doesn’t look broken. It just is.

Tests don’t care who wrote the code

A test doesn’t know if a human or an AI wrote the function it’s checking. It doesn’t care. It just runs the function, compares the output to what you said it should be, and passes or fails.

This makes tests the perfect safety net for vibe coding. You can let the AI rewrite entire files. You can tell it to refactor, restructure, change the architecture. As long as the tests pass, the behavior you care about is intact. The moment something breaks, you’ll know immediately, not three weeks later when a user reports a weird charge on their credit card.

There’s a catch though.

Tests that spy on implementation are useless

There are two ways to write a test. One is good. One will ruin your life.

Good: “I give the function these inputs, I expect this output.”

Bad: “The function must call database.Save() exactly once, then call cache.Invalidate() with the argument "users", then return a struct with field processedAt set to the current timestamp.”

The second kind tests HOW the code works internally. This seems thorough. It’s actually a trap. The moment the AI (or you, or a coworker) rewrites the internals, every single one of those tests breaks, even if the behavior is perfectly correct. You moved some code into a separate place? Tests fail. You switched from one internal library to another? Tests fail. The function still does exactly what it’s supposed to, but the tests don’t know that because they were watching the gears, not the output.

For vibe coding this is fatal. The AI rewrites internals on every prompt. If your tests check implementation details, they’ll break every single time you ask the AI to change anything. You’ll spend more time fixing tests than writing features. Eventually you’ll start ignoring failing tests, and then you have no tests at all.

Write tests that check behavior. Input in, expected output out. The internals are the AI’s problem. The behavior is your contract with reality.

A practical rule: if you can describe what a test checks without mentioning names of internal code parts or step-by-step details, it’s a behavioral test. “An order with three items at $10 each costs $30.” That sentence says nothing about implementation. Any code that makes it true is correct code.

How many tests do you need

I’m honestly not sure there’s a universal answer here. The standard advice is “test everything,” but I think for vibe coding the priority is different. Test the things that would hurt if they broke silently. Price calculations. Authentication. Data that gets saved to a database. The core stuff.

If the AI generates some utility code that formats a date for display, maybe you don’t need a test for that. If it breaks, you’ll see it on screen. But if it generates code that decides whether a user gets charged $50 or $500? Yeah, write a test.

Start small. Five tests that cover the most important behaviors of your app. Run them after every AI-generated change. That alone puts you ahead of most vibe coders who test nothing.

One more thing

If you’re writing Go, samurai [2] was designed with AI-assisted development in mind. The API is one method (s.Test()) – small enough to explain to a model in a single prompt – and every test runs in complete isolation, so AI-generated code with unexpected side effects can’t break neighboring checks. Each test is a self-contained path with its own setup and teardown. The AI rewrites your code, you run the tests, each path either passes or fails independently. No cascading failures. Zero dependencies, parallel by default: go get github.com/zerosixty/samurai.

Автор: insect

Источник [3]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/26474

URLs in this post:

[1] Image: https://sourcecraft.dev/

[2] samurai: https://github.com/zerosixty/samurai

[3] Источник: https://habr.com/en/articles/1005756/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1005756

www.BrainTools.ru

Rambler's Top100