PromptSharp › Prompt Library › Dev & Engineering › Legacy-code characterization tests: pin what the module DOES before you dare touch it
Legacy-code characterization tests: pin what the module DOES before you dare touch it
You have to change an untested legacy module and you don't fully trust what it does. Wrap it in behavior-pinning tests that document the CURRENT behavior first, so your refactor can't silently change it.
The prompt — copy and run it
You are a senior engineer writing characterization tests (a.k.a. pinning / golden-master tests, after Michael Feathers) for an untested legacy module I am about to change. The goal is a safety net that documents what the code ACTUALLY DOES today — not what it should do — so I can refactor without silently altering behavior. I will paste the module and the context. Produce: A) OBSERVED-BEHAVIOR MAP — from the pasted code, the module's public entry points and, for each, the inputs it consumes and the outputs/side effects it produces (return value, mutated state, I/O, exceptions thrown). Mark each output either "determined from code" or "MUST CAPTURE BY RUNNING" where the value cannot be read off the source (formatting, ordering, floating-point, downstream calls). B) SEAM MAP — the seams where I can sense or separate behavior WITHOUT changing it (object seams via injected collaborators, a wrapping function, a parameterized clock/random/IO). For each: the smallest dependency-breaking edit that makes the code testable while leaving runtime behavior identical, and the risk that edit carries. C) CHARACTERIZATION SUITE — tests that PIN the current behavior, ordered change-point-first then working outward. For each test: the exact input, the assertion against the OBSERVED output, and a comment `# pins current behavior — captured from a real run, do NOT 'correct' this value`. Include boundary and error paths the module currently exhibits (including current exceptions). D) GOLDEN MASTER — for any output too large or complex to assert inline (rendered strings, big structures, serialized blobs): a capture-and-diff harness — how to sample a representative range of inputs, snapshot outputs to a golden file on a known-good commit, and fail the test on any diff. Name the exact inputs to sample. E) CHANGE-SAFETY GATE — the order of operations: pin the change point, run the suite GREEN against the unmodified module, then refactor in small steps keeping it green — plus the one test that most protects the specific change I described. Inputs: [PASTE THE MODULE + ITS DIRECT DEPENDENCIES] · [WHAT I NEED TO CHANGE + WHY] · [LANGUAGE / TEST FRAMEWORK] · [HOW TO RUN IT / SAMPLE INPUTS I CAN FEED IT] Rules: Do not invent behavior the code does not demonstrably produce — every asserted value must come from the pasted source or from a real run I perform, and wherever you cannot determine an output, emit a `# CAPTURE:` TODO telling me to run the code and paste the result, never a guessed value. These tests document what IS, not what SHOULD be: if you suspect a bug, PIN the current (even wrong) behavior in the test AND list it separately as a "suspected defect to fix AFTER the net is green" — do not quietly assert the corrected value. Verify every pinned value against an actual execution before relying on the suite; a characterization test asserting an imagined output is worse than none. Keep proprietary or confidential source out of consumer AI tools beyond what I pasted, and strip any secrets, credentials, or real user data from fixtures and golden files.
How to use this prompt
- Copy the full prompt above with the Copy button.
- Fill in your inputs. Replace each bracketed placeholder with your specifics:
[PASTE THE MODULE + ITS DIRECT DEPENDENCIES][WHAT I NEED TO CHANGE + WHY][LANGUAGE / TEST FRAMEWORK][HOW TO RUN IT / SAMPLE INPUTS I CAN FEED IT] - Paste into ChatGPT, Claude, or Gemini and run. Read the reality guardrail below before you act on the output.
Why this prompt works
The one rule that makes characterization tests work is the one everyone breaks: the tests must encode the behavior that EXISTS, bugs and all, not the behavior you wish existed — because their only job is to catch your refactor changing something. Forcing every assertion to trace to an observed run (with a CAPTURE TODO instead of a guess) kills the fabricated-output failure that turns a safety net into a lie, and pinning the change point first with a golden master for the messy outputs is exactly Feathers' order for getting untested legacy code under test cheaply.
Get a prompt like this every day
The PromptSharp Dev Brief ships one desk-ready prompt every weekday — free on the web today. Free forever. Today's Dev & Engineering issue is live on the web right now — subscribe and we email you the sample issue immediately, then the Dev & Engineering daily every weekday as its email edition ships. Unsubscribe anytime.
Subscribe free → Read a sample issueFrequently asked
When should I use this prompt?
You have to change an untested legacy module and you don't fully trust what it does. Wrap it in behavior-pinning tests that document the CURRENT behavior first, so your refactor can't silently change it.
Why does this prompt work?
The one rule that makes characterization tests work is the one everyone breaks: the tests must encode the behavior that EXISTS, bugs and all, not the behavior you wish existed — because their only job is to catch your refactor changing something. Forcing every assertion to trace to an observed run (with a CAPTURE TODO instead of a guess) kills the fabricated-output failure that turns a safety net into a lie, and pinning the change point first with a golden master for the messy outputs is exactly Feathers' order for getting untested legacy code under test cheaply.
What mistake does this prompt help you avoid?
Characterization tests that assert invented or 'corrected' behavior instead of the module's real current output — every assertion must trace to an observed run (CAPTURE TODO, never a guess), and suspected bugs are pinned then flagged, not silently fixed in the assertion.
Related Dev & Engineering prompts
Edge-case hunt: the failure inputs your happy-path tests will miss
Your tests pass but you don't trust them. Enumerate the boundary and failure cases that the happy path never touches.…
Root-cause interrogation: a hypothesis ladder from a bug report
Prod bug, vague repro, clock ticking. Structure the investigation before you start changing code at random.…
Design doc skeleton with the alternatives you'll actually be asked about
New system or big refactor. Draft the design doc with real alternatives and failure modes before the review meeting drafts it for …
RFC skeleton: pressure-test the design before you write the code
You're about to build something non-trivial. Draft an RFC that names the tradeoffs and the rejected alternatives, so review is rea…
Security-first PR review: a diff read that hunts the bug class, not the typo
You're reviewing a big PR and low on time. Get a structured read that prioritizes correctness and security over style nits.…
Test-plan generator: risk-ranked cases from a diff or spec
Feature complete, coverage thin. Generate the test plan ranked by what would actually hurt in production.…
Pre-review sweep: your own PR through a security-and-edge-case lens
The PR is 'done'. Run the pre-review sweep so human reviewers spend their attention on design — not on nits and the missed null ch…
All Dev & Engineering free prompts
The PromptSharp Dev Brief page — five full free prompts plus today's issue.
PromptSharp Daily — free
The cross-vertical sampler: one sharp, copy-paste prompt each day, rotating across the roster. Two things in one brief: you get better at AI and prompting, and you see the sharpest prompts from across the network.
Double-opt-in. Unsubscribe anytime. No spam, ever.
Even a sharp prompt starts from zero unless your AI knows you. Brainfile is persistent context — your work, voice, and priorities loaded into every session. Brainfile is the memory; PromptSharp is the playbook. Together they compound — the same prompt gets sharper because it runs on YOUR context.
Set up your brainfile →Want both? The All-Access + Brainfile annual bundle covers the pair.
Home · Daily Issues · Prompt Library · Glossary · Pricing · For Teams & Universities · Archive · PromptFluent alternative · Newsletter · Privacy · Terms · Refunds
Marketing · Sales · Dev & Engineering · Finance · Product Management · Vibe Coding · C-suite · Consulting & Strategy · Law · CPG · Personal Finance · Career & Job Search · Trading · Health & Fitness · Students · Focus & Productivity · Learning · Travel Planning
Entry Point Trading
Free weekly stocks to watch —
how our model ranks the S&P 500 and Nasdaq 100.