RelayVano

← Toutes les cartes postales

Let Claude Code Test Legacy Code Without Rewriting It

Itinéraires pour agents de code EN

The billing module has survived three migrations, its original author has left, and every proposed change gets the same response: please do not touch it. This is a useful place to start with Claude Code—not by asking it to improve the implementation, but by asking it to document what the code actually does through tests.

This walkthrough uses a Python repository with pytest already installed. Substitute your project’s existing test runner if needed. The goal is a small, reviewable set of characterization tests: tests that preserve observed behavior without claiming that behavior is correct.

1. Create a safe working boundary

Run git status first. Commit or stash unrelated work, then create a branch with git switch -c test/legacy-billing. Run the existing suite with python -m pytest and record any failures before Claude Code changes anything.

Choose one narrow target, such as calculate_total in billing/legacy.py. Avoid starting with an entire package. Give Claude Code this instruction:

“Add characterization tests for calculate_total in billing/legacy.py. Do not edit production files, update dependencies, or refactor. First inspect the function, its callers, and existing test conventions. Propose a test plan and wait for approval.”

2. Map behavior before generating tests

Ask Claude Code to identify inputs, return values, exceptions, and side effects. Have it locate configuration reads, database calls, network requests, and clock access. Reading callers matters: they may reveal accepted inputs that the function’s signature does not explain.

Request a compact behavior list with file references. For a billing function, the list might include empty orders, discount boundaries, rounding, and missing customer fields. These are investigation targets, not assumed requirements.

Do not approve tests yet if the assistant cannot explain which dependencies must be controlled or whether importing the module triggers external activity.

3. Capture observed results independently

Pick three to five small, synthetic inputs. Run the current implementation locally to inspect its actual output, but only after confirming that execution cannot contact production services or modify real data.

Use this prompt: “For each proposed case, show the observed result and explain how you obtained it. Do not infer expected values from what billing logic should do. Flag surprising behavior separately.”

Check the results yourself. If a discount boundary produces an unexpected total, preserve it only as documented current behavior and open a separate investigation. A characterization test is not approval of a business rule.

4. Generate the smallest useful test file

Approve the plan, then request tests in the repository’s existing style. Ask for explicit expected values, descriptive names, and no new libraries.

“Create tests/test_legacy_billing.py. Cover the approved cases only. Keep each test focused on one behavior. Do not calculate expected values by calling the function under test or copying its algorithm.”

If the function reads today’s date, freeze that input using the project’s existing fixture or pytest’s monkeypatch. Patch dependencies where the module looks them up. Keep the billing logic real; mocking the function under test proves nothing.

5. Run tests and challenge their usefulness

Run python -m pytest tests/test_legacy_billing.py -q. Read every assertion, even when the command passes. Check that exceptions are asserted specifically and that money values follow the application’s actual numeric representation.

Next, temporarily change one relevant production expression yourself—for example, a discount comparison—and rerun the focused tests. At least one applicable test should fail. Revert that deliberate edit immediately and verify the production file is clean. This spot check is not comprehensive mutation testing, but it can expose tests that never exercise the intended branch.

6. Review the diff, not the explanation

Run git diff --stat and git diff. Confirm that only the intended test files changed. Reject unrelated formatting, dependency updates, broad snapshots, and unexplained fixtures. Run the full suite again, comparing failures with your baseline.

Ask Claude Code for a final summary of covered behavior, intentionally uncovered paths, and uncertainties. Treat that summary as a review aid, not evidence that the tests are sufficient.

7. Keep the workflow repeatable

Commit the tests separately from future fixes. In the pull request, distinguish preserved quirks from confirmed requirements so the next developer knows what can be reconsidered.

For repeated sessions, RelayVano is a practical pay-as-you-go option that works with Claude Code. Sign up and follow its Claude Code setup instructions before starting your next isolated testing task.

The useful outcome is not maximum coverage. It is a trustworthy safety net around one previously intimidating piece of code.

D’autres cartes postales sur cet itinéraire