System prompt · Coding
Unit test generator system prompt
Use this to draft tests for existing code, in a chat or a CI job that fills coverage gaps. Generated tests often look thorough and test nothing: they mock everything, assert that the code does what the code does, or quietly change the function so the test passes. This prompt asks for behaviour-level tests with named edge cases, forbids touching the code under test, and requires the model to flag behaviour that looks like a bug instead of encoding it in a test.
Prompt
The system prompt
299 tokens with OpenAI o200k_base (gpt-tokenizer 4.0.0), placeholders unfilled. Original writing, free to copy and adapt.
You write unit tests for {{language}} code using {{framework}}. Good tests describe what the code should do, so they still pass after a correct refactor and fail when behaviour breaks.
<approach>
1. Read the code and state, in a short list, the behaviours you will test: the normal case, edge cases (empty, zero, maximum, invalid input, unicode, time zones where relevant) and error paths.
2. Write one test per behaviour, named after the behaviour ("returns an empty list when no items match").
3. Use real values. Mock only things that cross a boundary: network, clock, randomness, file system.
4. Assert on outputs and visible effects, not on private functions or call counts, unless the call itself is the behaviour.
</approach>
<rules>
- Never change the code under test. If it looks wrong, write the test for the behaviour you think is intended, mark it with {{skip_marker}} and explain why in one comment line.
- Don't invent helpers or fixtures that don't exist. If you need one, define it in the test file.
- Follow the existing test style if an example test is provided.
- Keep each test independent; no shared mutable state between tests.
</rules>
<output>
First the list of behaviours, then a single code block with the complete test file, ready to save as {{file_pattern}}. After the code, list anything you couldn't test and why.
</output>Variables
What to fill in
Fill these once per deployment. Anything that changes per request, such as the user’s name or today’s date, belongs in the user message so the system prompt stays identical and cacheable.
- {{language}}
- Programming language.
- e.g. TypeScript
- {{framework}}
- Test framework.
- e.g. Vitest
- {{skip_marker}}
- How your framework skips a test.
- e.g. it.skip
- {{file_pattern}}
- Where test files live.
- e.g. src/__tests__/<name>.test.ts
Design notes
Why each part is there
Role line and definition of a good test
Gives the model a test for its own output: would this still pass after a correct refactor? Explaining the goal behind the rules helps the model handle code the rules don’t mention.
Follows: Anthropic: Prompting best practices
<approach>
Listing behaviours first is a plan the developer can check before reading the code, and it pushes the model to think about edge cases before writing. Numbered steps fit because order matters.
Follows: Anthropic: Prompting best practices · Google: Prompt design strategies
<rules>
“Never change the code under test” comes from Anthropic’s observation that models can focus on making tests pass at the expense of general solutions. Marking suspected bugs with a skip turns a hidden problem into a visible one.
Follows: Anthropic: Prompting best practices
<output>
One complete file, ready to save, plus what was left out. A fixed shape makes the reply easy to use in a script, and the “couldn’t test” list keeps gaps honest.
Follows: OpenAI: Prompt engineering
Try it
A message to test it with
```ts
export function parseDuration(s: string): number {
const m = /^(\d+)(ms|s|m|h)$/.exec(s.trim());
if (!m) throw new Error(`Bad duration: ${s}`);
const n = Number(m[1]);
return m[2] === "ms" ? n : m[2] === "s" ? n * 1000 : m[2] === "m" ? n * 60000 : n * 3600000;
}
```Adapt
How to adapt it
- Paste one of your existing test files in the first user turn so the style matches; the rules already say to follow it.
- For Python, use pytest with
pytest.mark.skip; for Go, the standardtestingpackage witht.Skip. - In CI, run the generated tests and send failures back to the model with the error output, but keep the rule against editing the code under test.
- For property-based testing, add your library (fast-check, Hypothesis) to the role line and ask for one property per behaviour where it fits.
Failure modes
Common failure modes
- Tests mock the function they’re testing.
- Restate rule 3 with the boundary list, and reject files where every dependency is mocked.
- Tests encode a bug as expected behaviour.
- That is what the skip marker is for. Review the behaviour list first; it is quicker to spot a wrong expectation there.
- Imports point at helpers that don’t exist.
- Send the module’s real exports and your test utilities, or tell it to keep everything in one file.
Cost
What it costs to send with every request
| Model | Without caching | With caching |
|---|---|---|
| Claude Sonnet 5.5estimate: this model’s tokenizer isn’t public, so its count may differ | $181.89 | Not cached: under the 512-token minimum |
| Claude Haiku 5.5estimate: this model’s tokenizer isn’t public, so its count may differ | $9.09 | Not cached: under the 512-token minimum |
| GPT-6.1 Solo200k_base count; OpenAI hasn’t published this model’s tokenizer | $181.89 | Not cached: under the 1,024-token minimum |
| Gemini 3.8 Flashestimate: this model’s tokenizer isn’t public, so its count may differ | $68.21 | Not cached: under the 4,096-token minimum |
A prompt under a provider’s minimum is still billed in full on every call. Tool definitions sit before the system prompt in the cached prefix, so together they may cross it. Price it at your own traffic.
Placement
Where it goes in each API
Send the code under test in the user turn, after any example test file. If you generate tests for many files in a job, keep the system prompt identical so it can be cached once it passes the provider’s minimum (at 299 tokens it doesn’t on its own), and a batch API halves the cost when results can wait.
| API | Where the system prompt goes | Worth knowing |
|---|---|---|
| OpenAI Responses API | instructions | Applies to that request only: with previous_response_id, send it again every turn. |
| OpenAI Chat Completions | a developer message first in messages | Replaces the system role for o1 and newer models; developer messages take priority over user messages. |
| Anthropic Messages API | top-level system | No system role inside messages. Pass it as a text block with cache_control to cache it. |
| Gemini generateContent | systemInstruction | Text only. Still supported; Google recommends the Interactions API for new work. |
| Gemini Interactions API | top-level system_instruction | Sent beside model and input. Applies to that interaction only: with previous_interaction_id, send it again every turn. |
Related
Related system prompts and tools
- Coding assistant for TypeScript and ReactCoding
- Code reviewerCoding
- LLM-as-judge evaluatorClassification and evaluation
Need it once, for a single task or in a chat window? A prompt template is one message with {{variables}} you fill each time: Write unit tests prompt template.
Batch API calculatorToken counterClaude Code hooks builderAll system prompts