From “I Don’t Write Code” to Behavioral Test Plans

Our CTO org has been pushing “shift left” for a while now, and the arrival of agentic AI tooling has turned that push into something closer to a mandate. The idea is straightforward: catch problems earlier, closer to where the code is written, instead of finding them in a manual test pass three sprints later. What’s less straightforward is what that means for the manual QAs on the team who built their entire skill set around clicking through an app and comparing what they see to a written test plan.

I had one QA respond to a conversation about writing more of her own tests with: “I’m a manual QA, I don’t write code.” That’s a completely reasonable position if the alternative being proposed is “learn Cypress.” But it’s the wrong frame for what’s actually needed. The gap isn’t that manual QA can’t write code — it’s that most manual test plans are written as a sequence of actions instead of a description of behavior, and that format doesn’t give anyone — human or AI — anything to build automation from.

What imperative test plans actually look like

Here’s a real pattern I’ve run into: a test plan with four test cases that specified exactly which VMs to target and which IP ranges to scan. The verification steps were things like “confirm the scan enumerates machines at 10.0.x.x through 10.0.x.y” and “verify device count matches expected total for that subnet.”

That’s not a test of a behavior. That’s a test of a specific environment on a specific day. If the subnet changes, the test plan is stale. If someone spins up a new VM, the “expected total” is wrong and nobody notices until the test fails for a reason that has nothing to do with a regression. Worse, nothing about that test case tells a developer — or an AI agent — what the system is actually supposed to do. It tells them what buttons got clicked against what IP addresses last time someone ran it manually.

The behavior buried inside that test case is something like:

Given a network segment with N reachable devices
When a scan is run against that segment
Then the scan should enumerate exactly those N devices,
with no false positives and no missed devices

That statement doesn’t care what the subnet is. It’s testable against any environment, it’s something a developer can write an integration test against, and — this is the part that matters for the AI angle — it’s specific enough that a coding agent can actually scaffold a test from it without guessing at intent.

The pitch: behavioral test plans as a pyramid coverage map

Once test plans are behavior statements instead of click-sequences, they can do something imperative plans never could: map cleanly onto the test pyramid.

For each behavior, ask where it’s actually covered:

  • Unit — does a unit test verify this in isolation?
  • Integration — does an integration test verify this against real dependencies (a real DB, a real scan engine, whatever’s relevant)?
  • E2E — does an end-to-end test verify this through the actual UI/workflow?
  • Uncovered — nothing verifies it yet.

That last bucket is the actionable one. Uncovered behaviors become backlog items: either the dev team writes the missing automated test, or — increasingly — a QA who “doesn’t write code” points an AI coding agent at the behavior statement and gets a scaffolded test back at the appropriate pyramid layer. The behavior statement is precise enough to be a prompt. That’s the whole point of writing it that way.

What’s left over after the pyramid is fully mapped isn’t nothing — it’s exploratory and UX testing. Once you know a behavior is correctly and repeatably verified by automation, the manual QA’s time is better spent on the things automation is bad at: does this flow feel confusing, is there a UI state that’s technically correct but a trap for the user, does an edge case exist that nobody thought to write a behavior statement for in the first place. That’s a better use of a skilled manual tester than re-clicking the same verified path every release.

Why this matters more right now

None of this is a new idea — BDD has been around for a long time. What’s changed is that agentic AI tooling makes the automation half of this loop cheap. A behavior statement that used to sit in a backlog for a sprint because nobody had time to write the Cypress test can now get a first-draft scaffold in minutes. That collapses the excuse that’s kept a lot of teams, mine included, stuck with imperative test plans: “we don’t have time to automate everything.” The bottleneck shifts from writing the test to writing the behavior statement clearly enough that a human or an agent can act on it — which is a much better problem for a QA team to have, and one their existing domain knowledge is actually suited for.

Where this gets messy

A few things I don’t have fully solved yet:

  • Mapping drift. A behavior marked “covered by integration test” today can silently stop being true if that test gets deleted or refactored into something else. Without some kind of traceability tag or ID linking the behavior to the test, the map lies to you.
  • Granularity. “The scan enumerates devices correctly” and “the scan handles a device that drops off mid-scan” are both plausible behavior statements at wildly different levels of detail. There’s a real skill in deciding how finely to slice these, and it’s not obvious yet what the right default is.
  • Not every manual QA wants to prompt an AI agent either. Moving from “I click buttons” to “I write precise behavior statements” is a real skill shift, even if it’s not “learn to code.” Don’t undersell how much of a change this still is for someone who’s spent years in a purely manual role.

I’m still working out the mechanics of how the mapping itself gets tracked — tags in the test code vs. a separate document — and I’ll probably write about that separately once I’ve actually tried both.