ChatGPT Prompt to Write Unit Tests for a Function

Setting the Scene

You have a small Python helper called parse_iso8601_duration. It turns strings like P1Y2M3DT4H5M6S into a datetime.timedelta, and it is used in a scheduling service where a wrong parse means a job fires at the wrong time. A colleague reviews the pull request and asks the question everyone dreads: “where are the tests?” You know you should write them, you know the edge cases are the whole point, and you also know that hand-writing twenty parametrized cases is tedious enough that it keeps getting postponed. That is precisely the gap a structured prompt closes.

The goal here is not for AI to invent a new function. The goal is to make ChatGPT produce a reviewable test file for a contract you already defined, including the nasty inputs (empty strings, duplicate designators, bad ordering) that people forget until production. Below is one prompt you can reuse for any pure function, the fields to change, the output you should expect, and the variations that fit different languages and frameworks.

The Reusable Prompt

Send the block below as a single message. The function contract is the part you edit; everything else is the reusable scaffolding.

You are a senior Python engineer who writes thorough but readable test suites with pytest.

Write unit tests for the function described below. Assume it lives in durations.py.

Function contract:
- Name: parse_iso8601_duration
- Input: a string in ISO-8601 duration format, for example P1Y2M3DT4H5M6S
- Output: a datetime.timedelta
- Supported designators: Y for years, M for months, W for weeks, D for days, then T followed by H, M, S
- Raise ValueError for any malformed or unsupported input
- A missing component defaults to zero
- A leading minus sign indicates a negative duration

Rules for the tests:
1. Use pytest with plain assert statements, no unittest classes.
2. Name every test function so it starts with test_ and states the behavior.
3. Use parametrize for the valid-format cases with at least 8 input and expected pairs.
4. Cover these valid cases: days only, time only, weeks, combined date and time, zero duration, negative duration, fractional seconds.
5. Cover these invalid cases: empty string, no leading P, unknown designator, duplicate designator, components out of order, lowercase designators.
6. Test boundary values: P0D, PT0S, and a span covering several years.
7. Include one test that asserts the return value is a timedelta instance.
8. Add a short comment above each test explaining the behavior it protects.
9. Do not write the implementation. Tests only.
10. End with the exact command to run this file.

Output the full file as one code block, then list every assumption you made about the contract.

The contract block is doing the real work. If you hand the model only a function name, it guesses the semantics and you get tests that assert the wrong behavior. If you hand it a contract with explicit error rules, it generates exactly the malformed-input cases that catch real bugs.

Variables to Swap

FieldWhat to changeExample variation
Function nameYour real symbolparse_money_cents
Input typeWhat the caller passesa decimal string like 19.99
Output typeWhat comes backan int number of cents
Error behaviorRaise, return None, or lograise ValueError on bad input
Frameworkpytest, unittest, or Jestpytest
Valid casesThe happy paths you care aboutround amounts, zero, large values
Invalid casesThe abuse you want blockedempty, symbols, negative for a count

Two fields repay extra care. The error behavior drives half the test file, so state it precisely; “handle bad input” is not a spec. And the valid cases list is where your domain knowledge lives, so name the real inputs you see in logs rather than generic placeholders.

Sample Output

Expect a runnable pytest file plus an assumptions list. A trimmed slice of the expected shape:

import pytest
from datetime import timedelta
from durations import parse_iso8601_duration

@pytest.mark.parametrize("value, expected", [
    ("P1D", timedelta(days=1)),
    ("PT1H", timedelta(hours=1)),
    ("P2W", timedelta(weeks=2)),
    ("P1DT2H3M", timedelta(days=1, hours=2, minutes=3)),
    ("P0D", timedelta(0)),
    ("PT0S", timedelta(0)),
    ("-PT30M", timedelta(minutes=-30)),
    ("PT1.5S", timedelta(seconds=1.5)),
])
def test_valid_durations_parse(value, expected):
    """protects the happy path across date, time, and mixed formats"""
    assert parse_iso8601_duration(value) == expected

@pytest.mark.parametrize("bad", ["", "1Y", "P1X", "P1D1D", "P1M1Y", "p1d"])
def test_invalid_durations_raise(bad):
    """protects the parser from silently accepting malformed input"""
    with pytest.raises(ValueError):
        parse_iso8601_duration(bad)

def test_returns_timedelta():
    """protects the public return type contract"""
    assert isinstance(parse_iso8601_duration("PT1S"), timedelta)

Run with: pytest test_durations.py -v

A good response includes the parametrized valid cases, a separate invalid block, a type assertion, and a run command. The assumptions list is your review checklist: if the model says “assumed months are 30 days,” you either confirm it or correct the contract and rerun.

Design Notes Behind the Prompt

Four choices shape the result. First, the output-type rule (“tests only, no implementation”) stops the model from burying real test logic inside an implementation file. Second, parametrize with a minimum count forces table-driven tests instead of one function per case, which keeps the file short and readable. Third, naming invalid cases explicitly, rather than saying “test bad input,” guarantees the malformed scenarios actually appear. Fourth, the assumptions list turns silent guesses into reviewable statements, which is the difference between trusting a test file and merging it blind.

Pitfalls to Watch

  • Tests that only assert no exception. A test that calls the function and asserts nothing else passes even when the value is wrong. Require equality checks against expected outputs.
  • Brittle floating-point equality. For PT1.5S compare against a timedelta, not a raw float, to avoid rounding surprises.
  • Over-mocking pure functions. A duration parser has no I/O, so it needs no mocks. Mocks here hide bugs rather than isolate them.
  • Copying the implementation into the test. If the test re-implements the logic, it agrees with the bug. Use literal expected values.
  • Ignoring the assumptions list. That list often reveals that you and the model disagree about month length or sign handling.

Adaptations

  • TypeScript and Jest: change the framework line to Jest and ask for describe and it blocks with toThrow for the invalid cases.
  • Property-based tests: add “Also propose three Hypothesis properties that should always hold, such as parse of a formatted value round-tripping.”
  • Coverage target: add “Ensure branch coverage of every error path and report which branches each test covers.”
  • Legacy function: append “The function currently returns None on bad input; write tests for current behavior first, then a separate group marked xfail for the desired behavior.”
  • Regression guard: paste a real bug report and add “Write one test that fails on the current code and passes once the bug is fixed.”

To keep the loop tight, run the file, paste any failures back, and ask for the minimal fix. For deeper testing setups, see ChatGPT Settings for Test-Driven Development, and when a test fails for reasons you cannot see, work through the ChatGPT debug workflow. To orient yourself in an unfamiliar module before writing tests, start with this prompt to explain a codebase.

Sources & Notes

Prompt pattern written for ChatGPT (GPT-4o and later) and adaptable to Claude and Gemini. The ISO-8601 duration grammar referenced here follows the public ISO-8601 standard for date and time intervals. Tested behavior: listing explicit invalid inputs produces more edge-case coverage than a general instruction to test errors. No external data or package versions were fetched; the example test file is illustrative and omits the implementation. Confirm the error type and month-length assumption against your own contract before merging the generated tests.

声明:1.本站所有文章,如无特殊说明或标注,均为本站原创发布。本网站中【文本生成/文生图】使用了DeeSseek人工智能生成内容技术, 算法来源说明:本网站未自行开发、训练或部署深度合成算法,所使用的人工智能算法来自:DeepSeek、Chatgpt、Google Gemini。 2.为了网站加载速度优化,本站预览图片进行压缩处理,所以有些不是太清晰,并不影响AI提示词生图、AI设计等内容。3.任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。--GUUNN.COM