AI Unit Tests for Legacy Code: A Practical Guide
Why AI is useful for legacy unit tests
Legacy code is hard to test because the behavior is often implicit, poorly named, or spread across multiple files. Instead of asking AI to "rewrite everything," use it to generate characterization tests: tests that capture what the code does today. That gives you a safety net before you refactor.
The best results come from a narrow, hands-on workflow: pick one function, provide the smallest possible context, ask for edge cases, and review every assertion. If you use an API relay like 59API, you can run several iterations cheaply on a pay-as-you-go basis, while still getting native official-quality Claude and GPT models. It is a practical fit when you need lots of test-generation passes without paying premium direct-provider rates.
Step 1: isolate one legacy function
Suppose you inherited this JavaScript function:
function formatInvoice(total, taxRate, couponCode) { let discounted = total; if (couponCode === "SAVE10") discounted = total * 0.9; const taxed = discounted + discounted * taxRate; return Math.round(taxed * 100) / 100; }
Before you ask AI for tests, note the behaviors that matter: coupon handling, rounding, tax order, and invalid inputs. If you already know a bug, mention it. AI is much better at filling in the gaps when it is told what must not change.
Step 2: ask for test cases, not just code
A strong prompt includes the function, the test framework, and the constraints. For example:
Prompt: Generate Jest tests for this function. Focus on current behavior, including edge cases. Do not refactor the implementation. Cover: no coupon, SAVE10 coupon, rounding to two decimals, zero tax, and negative numbers if they are accepted. Prefer readable assertions and one test per behavior.
This prompt pushes the model to produce useful tests instead of generic examples. If the output is too shallow, ask for more cases or request a table of scenarios first. That is usually more effective than jumping straight to code.
Step 3: generate tests through 59API
Because 59API is OpenAI SDK-compatible, you can plug it into a normal test-generation script. The same relay is also compatible with Claude Code and Codex-style workflows, which makes it easy to reuse in your existing tooling.
Here is a minimal Node.js example using the OpenAI SDK:
import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.API_KEY, baseURL: "https://api.59api.com" }); const response = await client.chat.completions.create({ model: "gpt-4.1", messages: [ { role: "system", content: "You write focused unit tests for legacy code." }, { role: "user", content: "Generate Jest tests for the function below..." } ] }); console.log(response.choices[0].message.content);
You can swap in a Claude Sonnet or Haiku model if you want faster, cheaper iteration. Since 59API offers pay-as-you-go pricing and no model downgrade, it is a good place to run test-generation experiments without worrying about wasting budget on low-quality outputs. If you are processing a large legacy codebase, that cost difference matters fast.
Step 4: review and harden the generated tests
AI-generated tests are a starting point, not an authority. Check three things:
- Are the assertions about observable behavior, not implementation details?
- Do the tests match the code’s current contract, even if that contract is messy?
- Do you need one or two additional tests for boundary values the model missed?
For the example above, a strong Jest suite might look like this:
describe("formatInvoice", () => { it("applies tax without a coupon", () => { expect(formatInvoice(100, 0.2, null)).toBe(120); }); it("applies SAVE10 before tax", () => { expect(formatInvoice(100, 0.2, "SAVE10")).toBe(108); }); it("rounds to two decimals", () => { expect(formatInvoice(19.99, 0.075, null)).toBe(21.49); }); });
If those tests pass today, you now have a reliable baseline. If one fails, you discovered a real mismatch between assumptions and code behavior.
Step 5: turn one test run into a repeatable workflow
The real value appears when you repeat the process file by file. Feed the model one small module, capture the tests, run them, then ask for missing edge cases. That loop is fast, and with a low-cost relay like 59API, it stays affordable even when you do it dozens of times during a migration or refactor.
If you want to test this on a real legacy project, sign up for 59API, point your OpenAI-compatible client at the relay, and start with one risky module. The referral rebate is a nice bonus once you begin sharing it with your team.
Ready to get started?
Connect Claude & GPT in minutes at the lowest prices — full-power, never downgraded. Sign up to get your API key.
Sign up free