How to Write Tests with AI
Ask the AI for tests the same way you ask for code: clear inputs, expected outputs, and edge cases. Then run the suite yourself. Green tests are the proof.
In short: describe behaviour → ask for tests first or right after the function → run pytest / node --test / JUnit → keep only tests you understand.
Why AI-written tests help
Writing every edge case by hand is slow. AI is good at listing empty, zero, negative and “unknown input” cases. Bad AI tests just copy the bug. You must read assertions and run them.
What a good test prompt has
- Behaviour: what “correct” means in one sentence.
- Framework: pytest, node --test, JUnit 5, xUnit, cargo test…
- Cases: happy path + at least two edges + one error path.
- Rules: “no network”, “no real clock”, “use temp dirs” when needed.
How writing tests flows
Example: discount helper + pytest
Here is final_price. Write pytest tests: no coupon, SAVE10, FLAT50 when price < 50 (floor at 0), unknown coupon raises ValueError. No extra files beyond test_discount.py.
def final_price(price: float, coupon: str | None = None) -> float:
if price < 0:
raise ValueError("price must be >= 0")
if coupon is None:
return round(price, 2)
if coupon == "SAVE10":
return round(price * 0.9, 2)
if coupon == "FLAT50":
return round(max(price - 50, 0), 2)
raise ValueError(f"unknown coupon: {coupon}")test_discount.py (tested here)import pytest
from discount import final_price
def test_no_coupon():
assert final_price(200) == 200.0
def test_save10():
assert final_price(200, "SAVE10") == 180.0
def test_flat50_floor():
assert final_price(30, "FLAT50") == 0.0
def test_unknown():
with pytest.raises(ValueError):
final_price(100, "BOGUS")cd code/tests
python3 -m pytest -q
# -> 4 passedHow to get useful tests
- Prefer tests that would fail if the code were wrong — not tests that only assert True.
- Name tests after behaviour (test_flat50_floor), not test1.
- Ask for table-driven tests in Go, or parametrize in pytest, when you have many similar cases.
- For legacy code: ask for characterisation tests that lock today’s outputs before you refactor.
- Run the suite in your IDE or CI — do not trust a chat that says “all passed” without a log.
| Pattern | Tip |
|---|---|
| Tests first (TDD-ish) | Ask for failing tests, then for code that passes them. |
| Code first | Paste the function; ask for tests that cover edges. |
| Bug fix | Write a failing test that reproduces the bug, then fix. |
| AI agent | Allow it to run the test command; keep approval on. |
Settings tip
- Put the exact test command in project rules (pytest -q, npm test, mvn test).
- In Copilot / Claude Code / Cursor Agent: “add tests and run them; stop if red.”
- Keep fixtures small. Do not paste production databases into the chat.
Quick quiz
1. What must you do after the AI writes tests?
Read the asserts and run the suite yourself.
2. What is a characterisation test?
A test that locks current behaviour before a refactor.
3. Name one edge case to always request
Empty/zero/negative input, or an unknown/invalid value.
4. Why avoid “assert True”?
It never catches a real bug.
Save tokens and money
Ask for the test file once with a clear case list. Do not regenerate the whole suite after every tiny code tweak — update the one failing case.