Prompt: Write Unit Tests

A copy-ready prompt for getting real, meaningful unit tests out of an AI model — covering edge cases, not just the happy path.

Updated Sep 2026 PIS score 83
The prompt
Open in Studio
You are a senior software engineer writing tests for the developers who'll maintain this code after you.

Objective: Write unit tests for the function below using {{TEST FRAMEWORK — e.g. Jest, pytest, JUnit}}.

Context: {{Paste any existing test file's style/conventions here, or say "no existing tests"}}

Constraints:
- Cover the happy path, at least two edge cases, and one invalid-input case
- Do not test implementation details — test observable behaviour only
- Use descriptive test names that state the expected behaviour, not the method name
- Do not mock anything that isn't an external dependency

Example: it("returns an empty array when given zero items", ...) — a name describing behaviour, not it("test1").

Output format: Return the test file in a single fenced code block, followed by a short bullet list explaining what each test group covers.

Before finishing, check that every test would actually fail if the corresponding bug were introduced.

Function:
```
{{PASTE FUNCTION HERE}}
```

Example

Input

TEST FRAMEWORK — e.g. Jest, pytest, JUnit: pytest
Paste any existing test file's style/conventions here, or say "no existing tests": no existing tests
PASTE FUNCTION HERE:
  def calculate_discount(price, percent):
      return price - (price * percent / 100)

Output

```python
import pytest

# Adjust this import to the module where calculate_discount is defined
from pricing import calculate_discount

def test_applies_percentage_discount_correctly():
    assert calculate_discount(200, 25) == 150
Show more
def test_returns_price_unchanged_when_discount_is_zero():
    assert calculate_discount(100, 0) == 100

def test_returns_zero_when_discount_is_100_percent():
    assert calculate_discount(50, 100) == 0

def test_raises_type_error_for_non_numeric_price():
    with pytest.raises(TypeError):
        calculate_discount("100", 10)
```
- Happy path: confirms a standard percentage discount is subtracted correctly.
- Edge cases: a zero discount leaves the price unchanged, and a 100% discount reduces the price to zero.
- Invalid input: a non-numeric price raises a TypeError instead of silently producing a wrong number.

All four tests assert on the function's return value only, so refactoring the internal calculation later won't break them as long as the output stays correct.

Why it works

  • Naming required case types (happy path, edge cases, invalid input) stops the model settling for three happy-path tests that look like coverage.
  • Testing behaviour rather than implementation keeps tests useful after a refactor instead of breaking on unrelated internal changes.
  • The 'would this test fail on a real bug' check filters out assertions that pass regardless of correctness.

Why the basic version fails

“Write tests for this function” usually gets you three happy-path tests and nothing else — no edge cases, no invalid input, sometimes no assertions that would actually catch a real bug. It looks like coverage without being coverage.

What this prompt fixes

Naming the required case types (happy path, edge cases, invalid input) forces the model to think about failure modes instead of just restating the function’s normal behaviour. The “would this test actually fail” check catches the common failure of tests that pass regardless of whether the code is correct.

Tips per model

  • Claude tends to follow the “test behaviour, not implementation” constraint closely — useful if you’re refactoring and don’t want brittle tests.
  • ChatGPT sometimes over-mocks; the “don’t mock anything that isn’t external” rule keeps tests meaningful.
  • Paste the real function, not a simplified version — tests generated against a stripped-down summary miss edge cases the actual implementation has to handle.