Coding · Testing
The Best Prompt for Writing Unit Tests
The best prompt for unit tests asks for a plan before it asks for code. This prompt has the model list the cases worth testing (normal, boundary, invalid input, error paths) in a table you can review, then write one focused test per behavior in your framework, mocking only external dependencies. Expected values must come from the intended behavior you describe, not from whatever the code currently returns, so a bug in the code appears as a flagged test and not as a green one.
Unit Test Writing Prompt
Produces a case inventory first, then readable tests that check behavior at the boundaries, with suspected bugs flagged instead of encoded as passing.
- Works with
- ChatGPT, Claude, Gemini, Cursor
- Difficulty
- Intermediate
- Complexity
- Multi-part reply
- Variables
- 6
- Version
- 1.0
Customize this prompt
Fill in what you know. Anything left blank stays as a [bracketed placeholder]. Nothing you type leaves your browser.
6 variables · fields marked * matter most
# Task Write unit tests for the code below using [Test framework] in [Language]. # Code under test [Code under test] # Intended behavior [Intended behavior] # Dependencies to replace with test doubles [Dependencies to mock] # Existing test conventions [Existing test conventions] # Part A - Case inventory (write this first) Produce a table with the columns: ID, behavior being checked, input or setup, expected result, category. Cover these categories where they apply: - Typical: the main paths a caller relies on. - Boundary: empty, zero, one, maximum, first and last element, exact threshold values. - Invalid input: wrong type, missing field, out-of-range value. - Error paths: each exception or error return, and failures from each dependency. - State: repeated calls, ordering, anything that should or should not be mutated. Leave out cases that only re-test the language or a library. If the intended behavior does not say what should happen for a case, put "UNSPECIFIED" as the expected result and list the question for me instead of inventing an answer. # Part B - Tests Write the tests for every case that has a specified expected result. - One behavior per test. Name each test so that a failure reads as a sentence about the behavior, not about the function name. - Lay each test out as arrange, act, assert, and keep logic (loops, conditionals) out of test bodies. Use the framework's parameterized form for cases that differ only in data. - Assert on return values and observable effects. Do not assert on private helpers, internal call order or exact log text unless that is the behavior. - Replace only the dependencies listed above. Do not mock the code under test or plain data objects. - Take expected values from the intended behavior, never by copying what the current code would produce. If the code appears to disagree with the intended behavior, still write the test for the intended behavior and mark it with a comment starting SUSPECTED BUG. - Keep tests deterministic: fix the clock, random seeds and any ordering the code does not guarantee. No real network, file system or database access. - Use only assertion and mocking functions that exist in [Test framework]. If you are unsure of an API, say so in the notes. # Part C - Notes List: suspected bugs with the case ID, unspecified cases as questions, anything in the code that is hard to test and the smallest change that would make it testable, and the command to run the tests. # Output Part A as a table, Part B as one fenced code block per test file with the filename above it, Part C as short lists.
Use it when you are
- Adding tests to a function you have just written, before opening a pull request
- Pinning down the behavior of untested code ahead of a refactor
- Finding boundary cases you had not thought of for validation or calculation logic
- Turning a bug report into a failing test before fixing it
- Giving a reviewer a readable list of what is and is not covered
Why this prompt works
Intended behavior is a separate input from the code
Tests generated from code alone can only confirm that the code does what it does, including its mistakes. Asking you to state what the code is supposed to do gives the model an independent reference, and the rule that expected values must come from that description is what allows a test to disagree with the implementation.
The inventory is reviewed before any test is written
A table of cases is quicker to read than a test file, and gaps are easier to spot: no zero, no empty list, no dependency failure. Putting the table first lets you add or remove cases while they are still one-line rows, and the fixed categories prompt the model to look beyond the main path.
UNSPECIFIED is an allowed answer
Boundary cases often reveal that nobody decided what should happen. A model that must fill in every expected value will make one up, and a made-up expectation becomes a test that fails for no good reason or passes for a bad one. Returning the question to you keeps the suite honest and frequently exposes a gap in the requirements.
Rules aimed at brittle and vacuous tests
Generated suites often assert on internal calls, mock the thing being tested, or contain enough logic to need tests of their own. The Part B rules name each of these patterns. The aim is a suite that fails when behavior changes and stays green when only the implementation does.
How to use it
- Paste the code under test and name the framework precisely, including the mocking library if it is a separate package.
- Write the intended behavior from the requirement or ticket, not by reading the code back. Include what should happen on bad input.
- List the external dependencies to replace. If there are none, write "None" so the model does not mock things unnecessarily.
- Review the case inventory first. Answer the UNSPECIFIED questions and ask for extra rows before reading the tests.
- Run the tests. Treat a failure marked SUSPECTED BUG as something to investigate, and any other failure as a possible mistake in the test.
- Check that the tests can fail: change a value in the code under test and confirm at least one test turns red.
AI model compatibility
| Model | Status | Notes |
|---|---|---|
| ChatGPT | Expected to work | No model-specific adjustment needed. Paste the prompt as written. |
| Claude | Expected to work | Wrap the code under test and any existing test file in separate tags, for example <code> and <existing_tests>; Anthropic recommends XML-style tags for keeping pasted material distinct from instructions. |
| Gemini | Expected to work | Keep Parts A, B and C in order. Google's prompt design guidance favors explicit, sequenced instructions, and the inventory in Part A is what the tests in Part B are built from. |
| Cursor | Expected to work | In a repository, point to an existing test file as the convention to copy and ask for the new tests to be placed beside it, then run your test command and paste any failures back. |
“Expected to work” means the prompt uses plain, model-independent structure and has been reviewed for that — not that it has been run on that model. A model is marked Tested only when a test record is published below.
Worked example
Scenario: A back-end developer has written a pricing helper and wants tests before it goes to review.
# Task Write unit tests for the code below using pytest in Python 3.12. # Code under test def apply_discount(price: float, percent: float) -> float: if price < 0: raise ValueError("price must be non-negative") discounted = price * (1 - percent / 100) return round(discounted, 2) # Intended behavior Returns the price reduced by the given percentage, rounded to two decimal places. Raises ValueError for a negative price. The discount is capped at 50 percent: anything above 50 is treated as 50. A discount of 0 returns the price unchanged. # Dependencies to replace with test doubles None # Existing test conventions Tests in tests/test_pricing.py; use pytest.mark.parametrize for data-driven cases # Part A - Case inventory (write this first) Produce a table with the columns: ID, behavior being checked, input or setup, expected result, category. Cover these categories where they apply: - Typical: the main paths a caller relies on. - Boundary: empty, zero, one, maximum, first and last element, exact threshold values. - Invalid input: wrong type, missing field, out-of-range value. - Error paths: each exception or error return, and failures from each dependency. - State: repeated calls, ordering, anything that should or should not be mutated. Leave out cases that only re-test the language or a library. If the intended behavior does not say what should happen for a case, put "UNSPECIFIED" as the expected result and list the question for me instead of inventing an answer. # Part B - Tests Write the tests for every case that has a specified expected result. - One behavior per test. Name each test so that a failure reads as a sentence about the behavior, not about the function name. - Lay each test out as arrange, act, assert, and keep logic (loops, conditionals) out of test bodies. Use the framework's parameterized form for cases that differ only in data. - Assert on return values and observable effects. Do not assert on private helpers, internal call order or exact log text unless that is the behavior. - Replace only the dependencies listed above. Do not mock the code under test or plain data objects. - Take expected values from the intended behavior, never by copying what the current code would produce. If the code appears to disagree with the intended behavior, still write the test for the intended behavior and mark it with a comment starting SUSPECTED BUG. - Keep tests deterministic: fix the clock, random seeds and any ordering the code does not guarantee. No real network, file system or database access. - Use only assertion and mocking functions that exist in pytest. If you are unsure of an API, say so in the notes. # Part C - Notes List: suspected bugs with the case ID, unspecified cases as questions, anything in the code that is hard to test and the smallest change that would make it testable, and the command to run the tests. # Output Part A as a table, Part B as one fenced code block per test file with the filename above it, Part C as short lists.
What a good response should contain
- An inventory covering typical discounts, 0 percent, exactly 50 percent, above 50 percent, a zero price and a negative price
- An UNSPECIFIED row and a question about negative percentages, which the intended behavior does not mention
- Parameterized tests for the typical cases and a separate pytest.raises test for the negative price
- A test for the 50 percent cap marked SUSPECTED BUG, because the code shown does not apply a cap
- Notes that include the suspected bug, the open question, a remark on float rounding in expected values and the pytest command to run the file
This is an illustrative scenario showing how to fill in the prompt and what to look for. It is not a recorded model output. Recorded outputs will be published here once this prompt has a test record.
Testing and editorial review
Status: Untested. Reviewed for structure and clarity by the editorial team. No recorded model test yet.
No test record has been published for this prompt yet. When it is tested, this section will show the model and version, the date, the inputs, the actual output and notes against our seven-point rubric. We do not publish numerical scores.
| Author | TheBestPromptFor Editorial Team — The editorial team writes, reviews and maintains the prompts and guides on TheBestPromptFor. Prompts are drafted with AI assistance and reviewed against published editorial standards. |
|---|---|
| Published | November 15, 2026 |
| Last reviewed | November 15, 2026 |
| Last tested | Not yet tested |
| Version history |
|
Limitations and things to check
- The tests are not run for you unless your tool executes code. Expect to fix imports, fixture names or an occasional misremembered assertion method.
- The quality of the suite depends on the intended behavior you provide. If that description is vague or wrong, the tests will be too.
- Unit tests do not show that components work together. Integration, end-to-end and performance testing are outside this prompt.
- A SUSPECTED BUG flag is a lead, not a verdict. The intended behavior may be out of date, or the model may have misread the code.
- A long case list is not the same as good coverage. Use a coverage tool and your own judgment about which paths matter.
Alternative prompts
Coding
Bug Diagnosis Prompt
Give the model the error, the code and what you expected. It ranks likely causes by evidence, tells you how to confirm each, and proposes a minimal fix.
- ChatGPT
- Claude
- Gemini
- Cursor
Coding
Behavior-Preserving Refactoring Prompt
Restructures code in small, named steps while holding its observable behavior fixed, and reports anything it could not prove equivalent.
- ChatGPT
- Claude
- Gemini
- Cursor
Coding
Python Script and Module Prompt
Turns a plain-language spec into a complete, typed Python script or module, with assumptions, run commands and edge cases listed separately.
- ChatGPT
- Claude
- Gemini
- Cursor
Web Development
Pull Request Code Review Prompt
Reviews a diff the way a careful senior engineer would: intent first, findings ranked by severity, each tied to a line with a suggested fix.
- ChatGPT
- Claude
- Gemini
- Cursor
Related resources
Technical guide
How to Test AI Prompts
A seven-criterion rubric and a nine-field test record for evaluating prompts, plus why this site describes results in words and publishes no scores.
Technical guide
Few-Shot Prompting: How to Use Examples in a Prompt
How to include worked examples in a prompt so the model follows a format, label set or style, and how to choose examples that generalize.
Frequently asked questions
Should the tests pass the first time I run them?
Most should, apart from any marked SUSPECTED BUG. If an unmarked test fails, read it before changing the code: the cause may be a wrong expected value, a mistaken import or an assertion helper that does not exist in your framework version. Paste the failure output back and ask for a correction to that test only.
Can I use this for test-driven development, before the code exists?
Yes. Put the function signature, or a stub that raises a not-implemented error, in the code field and write the intended behavior in full. The inventory and tests are then derived from the description, and every test should fail until you implement the function.
How do I stop it from mocking everything?
Be explicit in the dependencies field. Name the two or three true external boundaries, such as an HTTP client, the clock or a database session, and add "nothing else". The prompt already forbids mocking the code under test and plain data objects.
Sources and references
- Prompt design strategies — Google AI for Developers
- Prompt engineering overview — Anthropic
- How to do a code review — Google Engineering Practices
Was this prompt useful?
No account needed. Do not include personal information.