Behaviour Tests Don’t Wait for Code Quality
Abstract
Most teams build features in the order PRD → product code → test code. That order looks at product code quality (maintainability, security, performance) first, and leaves whether the feature does what the PRD promised for later.
Product code has two things to ensure: behaviour and code quality. Behaviour has fewer dependencies, so it can be ensured first.
This post makes two points:
- Test the PRD, not the code.
- Test behaviour without waiting for code quality.
Why
Tests written after the code read the code and assert what it does. If the implementation and the PRD disagree, the test judges the misreading as a pass.
Contradictions and gaps in the PRD can get filled by an engineer’s guess mid-implementation, which leads to rework later. When tests are generated from the PRD, they show up as expected outcomes you can’t write, and they become questions for the PRD owner.
What
By behaviour tests I mean integration and E2E tests, which check behaviour observable from outside. Integration tests cover every scenario against fake dependencies, and E2E tests cover the critical paths in a real environment.
Get Yusuke Kita’s stories in your inbox
Join Medium for free to get updates from this writer.
PRD → test code → product code describes dependency, not time.
PRD
│
▼
executable spec
│ │
▼ ▼
test code product code ◀── code quality- Executable spec: the behaviour the PRD promises (states, events, expected outcomes), written so tests can be generated from it.
- Test code takes its expected outcomes only from the executable spec, never from the implementation.
- Product code depends on both behaviour and code quality.
Product code has to satisfy both behaviour and code quality, but test code needs only behaviour. That’s why behaviour tests can be written and run without the final product code.
The final test code runs against the actual product code. But what a test expects is decided by the spec alone, never by reading the product code.
How
In the AI era code is easy to generate, so even if you write the tests first, you can also generate the product-side implementation that runs them. Generate throwaway code together with the tests from the executable spec, and run them. The throwaway code can go; the tests stay and run as they are against the actual product code, because they encode the PRD, not the throwaway code.
In practice:
- If the PRD doesn’t give an expected outcome, ask the PRD owner instead of guessing one.
- Assert only observable outcomes, and don’t depend on implementation details.
- Code quality can be ensured at the same time, as long as behaviour tests don’t wait for it.
BDD’s Given/When/Then and specification by example share the same idea. ESDD, which I’ve been building (The Executable Spec Pipeline), is one way to automate it. It turns the PRD into a checkable UseCase IR, sends contradictions and gaps back to the PRD owner as questions, and generates tests from the approved IR.
Summary
- Test the PRD, not the code. Tests built from the PRD find misread requirements; tests built from the code miss them.
- Test behaviour without waiting for code quality. What tests expect is decided by behaviour alone, so they can run against throwaway code first. Quality is improved from there.
Now that code is easy to generate, there’s no reason to wait for finished code before checking behaviour. There are two things to ensure, behaviour and code quality, and behaviour has fewer dependencies, so ensure it first.





