# I Haven't Written a Test in a Year
## And My Test Suite Is Better for It
*Draft for public journal - January 2026*
---
I haven't written a test in a year.
For a developer who built an entire philosophy around "Bugs as Missing Test Cases," this sounds like professional negligence. Like I've abandoned the craft.
The tests exist. I just didn't write them.
---
## What Actually Happened
AI writes the tests now. I review them.
This isn't vibe-testing. I don't blindly accept whatever the AI generates because it looks plausible and the green checkmarks feel reassuring. This is a systematic workflow:
1. I implement a feature (or AI does, and I verify)
2. I describe what the tests should cover
3. AI generates the test file
4. I review the generated tests
5. I run them, verify they test what matters, request changes if needed
6. Tests get committed
Most days this works. But step 4 is where it breaks down more than I'd like to admit. Sometimes I'm three reviews deep and realize the AI keeps generating tests that pass but don't actually prove anything. They're testing the happy path six different ways while ignoring the one boundary condition that caused last month's production incident. That's when I have to dictate the test structure myself.
The 20-30 minutes I used to spend writing a test file? Now I spend 10 minutes reviewing one. The output is the same. Often better, because AI doesn't get bored writing the tedious edge cases.
But the skill has fundamentally changed. I used to write good tests. Now I catch bad tests.
Same outcome. Different process. Different expertise.
---
## What I Review For
When AI generates a test file, I'm not checking syntax. I'm checking judgment.
**Does it test the right thing?**
AI tests what it sees. I know what the code is *supposed* to do, which isn't always what it does. The test needs to verify intent, not just current behavior.
**Does it catch the edge cases I know about?**
I've lived in this codebase for years. I know where the dragons are. If the AI-generated tests don't poke at the known failure modes, they're not good enough.
**Is it testing behavior or implementation?**
Bad tests break when you refactor. Good tests break when you break functionality. AI often couples too tightly to implementation details. I push back toward behavior.
**Will it break for the wrong reasons?**
Date-dependent tests. Order-dependent assertions. Hardcoded values that become false in six months. AI doesn't feel the pain of maintaining tests over time. I do.
This review process takes domain knowledge. It takes experience with what breaks. It takes judgment that AI doesn't have.
### A Review in Practice
I asked Claude to generate tests for a service that processes subscription renewals. The first version came back with something like this:
```ruby
test "processes renewal successfully" do
subscription = create(:subscription, status: "active",
expires_at: Time.current + 1.day)
result = RenewalService.call(subscription)
assert result.success?
assert_equal "active", subscription.reload.status
end
test "handles expired subscription" do
subscription = create(:subscription, status: "active",
expires_at: Time.current - 1.day)
result = RenewalService.call(subscription)
assert result.success?
assert_equal "renewed", subscription.reload.status
end
```
Both tests pass. Both tests are wrong.
The first test renews a subscription that isn't due yet. Why would you renew something that doesn't expire for another day? It should either be a no-op or an error. The second test asserts `success?` for an expired subscription, but the actual business rule is that subscriptions expired for more than 30 days should *fail* renewal and require manual intervention.
The AI tested the code paths. I know the business rules. After review, the tests looked like this:
```ruby
test "renews subscription expiring within 7 days" do
subscription = create(:subscription, status: "active",
expires_at: 3.days.from_now)
result = RenewalService.call(subscription)
assert result.success?
assert_equal "active", subscription.reload.status
assert subscription.expires_at > 3.days.from_now
end
test "skips subscription not yet due for renewal" do
subscription = create(:subscription, status: "active",
expires_at: 30.days.from_now)
result = RenewalService.call(subscription)
assert result.skipped?
end
test "fails renewal for subscription expired over 30 days" do
subscription = create(:subscription, status: "active",
expires_at: 45.days.ago)
result = RenewalService.call(subscription)
refute result.success?
assert_includes result.errors, "requires manual review"
end
```
Same service. Completely different tests. The difference isn't syntax. It's knowing that "expired" means different things depending on *how long ago* it expired.
This is what test review looks like. The AI wrote plausible tests. I caught the ones that would have let real bugs through.
---
## What I've Gained
**Coverage I wouldn't have written.**
How many tedious edge cases do you skip because life is short? AI doesn't skip. It will generate the boring permutation tests that you technically know you should write but never do. My coverage is higher because AI has more patience than I do. Sometimes it tests something and I think: "Oh. Yeah. That could definitely break."
**Faster iteration on test quality.**
"This test is too coupled to implementation. Rewrite it to test behavior." That sentence takes three seconds to type and gets me a better test faster than rewriting it myself.
**More time for test strategy.**
What should we test? How should the test suite be organized? What's the failure mode we're not covering? These strategic questions matter more than the syntax. Offloading the typing lets me think at a higher level.
---
## What I've Lost
**Muscle memory for test syntax.**
I used to type `assert_equal` without thinking. Now I sometimes pause on the argument order. The syntax has faded because I don't practice it.
**The design pressure of writing tests first.**
This is the loss I can't fully account for. Real TDD, writing tests before implementation, forces you to think about the interface before you build it. It's a design tool disguised as a testing tool. When AI writes tests after the fact, that design pressure disappears. Has the design quality of my code changed? I genuinely don't know. I haven't had a clear "this design suffered because I skipped TDD" moment, but the absence of evidence isn't evidence of absence. The design feedback loop that TDD provides is subtle. It's possible I'm accumulating design debt I can't see yet. That uncertainty is the most honest thing I can say about it.
Something happens when you manually type out test cases. You think of cases you wouldn't have thought to ask for. The writing *is* the thinking. Reviewing someone else's tests (even AI-generated ones) doesn't trigger the same discovery process.
And if I had to write tests without AI tomorrow, I'd be slower than I was a year ago. If my internet went down and a critical test needed writing, I'd need to look up assertion syntax I used to know cold. That dependency is real.
---
## The Uncomfortable Truth
**I'm a worse test-writer than I was a year ago.**
If you put me in a room with a whiteboard and asked me to write test cases from scratch, I'd be rustier than I was in early 2025. The skill has atrophied from disuse.
**I'm a better test-reviewer than I was a year ago.**
I've spent a year reading and critiquing AI-generated tests. I know what bad AI tests look like. I know what's missing, what's over-specified, what will break in six months. My review skills are sharper than ever.
**These are different skills.**
Writing and reviewing are not the same expertise. The market doesn't recognize this yet. Job interviews still ask you to write tests on a whiteboard. They don't ask you to review AI-generated tests for quality.
But the job has changed. The interview just hasn't caught up.
---
## The Team Question
There's a social dimension I haven't seen discussed much.
When I review a teammate's pull request, I'm now evaluating their hand-written tests with a reviewer's eye trained on AI output. I notice different things. I'm more attuned to implementation coupling and fragile assertions because that's what I catch in AI-generated tests all day.
But the reverse is also true: when my AI-generated tests go through code review, does anyone notice? Should they? I don't hide it, but I also don't label every test file "generated by Claude." The tests are committed under my name, reviewed by me, and I stand behind their quality.
The awkward part is the skill asymmetry. A teammate who spends 30 minutes writing a test file is practicing a skill I'm letting atrophy. If we both lose access to AI tools tomorrow, they're better prepared than I am. I've traded that resilience for throughput and coverage. That's a bet, and I haven't fully reckoned with the downside.
---
## What This Means
Testing expertise isn't obsolete. It's transformed.
The knowledge of *what* to test matters more than ever. Knowing which edge cases break, understanding the domain, recognizing when a test is too fragile. That judgment is exactly what AI lacks. The expertise is the same; the expression is different.
**Knowing what to test matters more than knowing how to type it.**
I still apply "Bugs as Missing Test Cases" every day, a principle I've followed for over a decade: every production bug reveals a test that should have existed. When something breaks, I still ask: "What test would have caught this?" The philosophy is unchanged. But the hands that write the test are different now.
**Quality judgment can't be automated (yet).**
AI can generate a test that passes. It can't generate a test that will still be valuable in two years. It can't weigh the maintenance cost against the coverage benefit. It can't feel which tests are worth having. That judgment is human.
**The skill transfer is real.**
A developer who never learned to write tests won't be a good test reviewer. You need to have written bad tests to recognize them. The foundation is still required. It's just not the daily practice anymore.
This is part of the broader implementor-to-orchestrator shift (a transition I explored in The Orchestrator Identity). The pattern holds for code, for tests, for documentation. The skill is verification and judgment, not production.
---
I haven't written a test in a year. But I've reviewed a thousand of them.
And when I interview for my next job, they'll ask me to write tests on a whiteboard. They won't ask me to review AI-generated tests for correctness, spot the business logic gaps, or evaluate whether a test suite will survive the next refactor. They'll test the skill I've stopped practicing and ignore the one I've been sharpening every day.
The job has changed. The interview hasn't. And I'm not sure which side of that gap I want to be on.
---
## Revision Notes (v4)
**Changes from v3:**
1. Removed all em-dashes from article body (12 instances across lines 18, 29, 38, 40, 59, 90, 120, 149, 185, 195, 199, 207). Replaced with periods, commas, or restructured sentences to match the em-dash-free style of Parallel SFTP v9.
2. Cut "Let me sit with that for a moment." (line 12). Performative pause doesn't match published voice.
3. Cut "But here's the thing:" (line 14). Classic AI transition phrase.
4. Cut "The gains are real." (line 128). Section heading already signals this.
5. Replaced "I won't pretend this shift is pure gain. There are real losses, and the biggest one still bothers me." (line 143) with "There are real losses."
6. Cut "Here's what I need to say out loud:" (line 161). Dramatic setup removed; section starts directly with bold statement.
7. Cut "Be honest:" from coverage gain question (line 131). Removed lecturing tone.
8. Cut "Here's a real example." (line 68). Led directly into the example.
9. Varied bold+colon pattern in Losses section. Last two items (edge case intuition, AI dependency) flow as unbolded paragraphs to break the template feel across 7 consecutive items.
**Previous changes (v3 from v2):**
1. Trimmed step 4 friction paragraph
2. Tightened "Coverage" gain
3. Added concrete example to "Speed when AI isn't available"
4. Added context sentence for "Bugs as Missing Test Cases"
5. Made Orchestrator Identity cross-reference explicit
6. Removed author bio placeholder
7. Updated revision notes
**Previous changes (v2 from v1):**
1. Removed TL;DR
2. Added subtitle "And My Test Suite Is Better for It"
3. Defined "vibe-testing" inline on first use
4. Added concrete before/after example of subscription renewal test review
5. Added friction to the 6-step workflow (step 4 breakdown)
6. Reordered to Gains before Losses for stronger emotional arc
7. Deepened TDD/design quality loss with genuine uncertainty
8. Added "The Team Question" section on social dynamics and skill asymmetry
9. Trimmed "Connection to Larger Theme" to single sentence in "What This Means"
10. Replaced safe closing with uncomfortable market mismatch ending
11. Merged "Fresh perspective" into "Coverage" in gains section
12. Changed "rustier than I was in 2024" to "rustier than I was in early 2025"
**Status: Publication-ready.** De-AI'd: zero em-dashes, no "here's"/"let me" constructions, varied formatting patterns.