BH3D Logo
Spec Coverage > Code Coverage

The Missing Metric in Software Testing: Spec Coverage

By Ben Houston, 2025-04-27

For decades, we’ve measured test quality by how much code it touches. If a line of code runs during a test, we say it’s “covered.”

But as we shift toward intent-based programming -- where code is generated from declarative specifications -- this model breaks down. Why?

Because we no longer care how much of the code was exercised. We care how much of the intent was verified.

Enter: Spec Coverage.

What Is Spec Coverage?

Spec Coverage measures the percentage of declared application intent that has been verified by tests.

It’s not about lines of code. It’s about purpose.

# Example intent spec
feature: user-authentication
  intent:
    - Users must log in with email/password
    - Passwords must meet complexity rules
    - Sessions expire after 24 hours
    - All endpoints require authentication

A test suite has spec coverage if it verifies each of these declared behaviors -- regardless of how the underlying code is structured.

Toward a Two-Phase Testing Process

Intent-based programming already separates specification from code generation. We should do the same for tests.

Here’s the improved workflow:

Phase 1: Generate a Declarative Test Plan

From the application spec, we generate a test plan in YAML. Each test case references an intent item and includes a human-readable description:

testPlan:
  - id: auth-001
    specRef: user-authentication/0
    description: 'Verify users can log in with valid email and password'
  - id: auth-002
    specRef: user-authentication/1
    description: 'Reject passwords that fail complexity rules'
  - id: auth-003
    specRef: user-authentication/2
    description: 'Ensure session expires after 24 hours of inactivity'

These test plans are durable, portable, and reviewable -- even before code exists. They’re the source of testing truth.

Phase 2: Generate Test Code from the Plan

The second step generates implementation code for each test case, ensuring that the test suite maps back to explicit intent:

// test/auth-001.test.ts
// linked to spec: user-authentication/0
it('auth-001: users can log in with valid email and password', async () => {
  const res = await login({
    email: 'test@example.com',
    password: 'StrongPass123!'
  });
  expect(res.status).toBe(200);
});

You now have a full trace:
Intent → Test Plan → Test Code → System Verification

Benefits of the Two-Stage Model

  • Declarative Traceability: Each test links back to its originating spec item, creating a provable audit trail.
  • Human-in-the-Loop Planning: Test plans are editable before code is generated, allowing engineers, QA, and even product managers to verify correctness.
  • Easy Regeneration: Changing the spec only regenerates affected test plans and implementations. No brittle coupling to source code.
  • LLM-Friendly: Language models can more easily generate test code when given clear, structured test plans as intermediate artifacts.

Rethinking Coverage

Under this model, we can define Spec Coverage like this:

specCoverage:
  totalSpecItems: 12
  totalTestPlanItems: 10
  totalTested: 9
  gaps:
    - specItem: user-authentication/1
      reason: no test yet

Forget whether a line of code was hit. Ask instead: Was each intent validated?

This is especially critical in AI-generated systems where:

  • Implementation is a black box
  • Code can be re-rendered anytime
  • Intent must be the invariant

Why Code Coverage Becomes a Liability

Relying on line-level code coverage in this new world is like checking whether your compiler touched every register. It’s irrelevant.

What you really want to know is:

Did we test everything we said this system is supposed to do?

That’s spec coverage.

The Future of Test Suites

This two-phase model transforms test suites into spec executors:

  • Specs define what the system should do.
  • Test plans enumerate the validations.
  • Test code operationalizes each test.
  • Spec coverage becomes the go-to metric.

We’re moving from “did the code run?” to “did the system fulfill its intent?”

Final Thoughts

Spec-first code generation changes how we write applications. Spec-first test generation will change how we verify them.

By separating test planning from test implementation, and anchoring everything in declarative specs, we unlock a more robust, traceable, and efficient way to test software.

Spec Coverage isn’t just a better metric -- it’s a better model.