Prompt Testing
Prompt testing checks that a prompt — the instructions, examples and variables an application sends to a language model — gives acceptable output for a fixed set of test inputs, and that each new version keeps what the previous one did well. You test it like any other part of the system: against a test basis, with designed test cases and recorded results.
Example: a store’s support assistant has a prompt that says "Answer in the customer’s language" and "Hand every complaint about a damaged item to a human agent". Its test set holds an Arabic question about delivery, a Hindi complaint about a broken kettle and an English request for a service the store does not offer. Each case states what every acceptable answer must do, so the same checks run against version 3 of the prompt today and version 4 tomorrow.
Why it matters
Prompts change more often than almost any other part of an LLM application, and a one-sentence edit can change behaviour in cases that seem unrelated. Nothing compiles or type-checks natural-language instructions: a prompt that reads better can still drop a policy condition, switch the answer language or stop escalating complaints. Without a test set and a recorded baseline, such regressions reach users unnoticed.
For the tester, prompt testing turns "the new prompt seems better" into evidence: which cases improved, which broke, on which model and prompt version. It also makes LLM defects easier to reproduce, because a report that names the prompt version, the model and the input can be re-run.
What exactly is under test
The guide on LLM testing showed that a system prompt is a specification written in natural language. What you version and test is slightly larger: everything your team controls that shapes the answer, treated as one configuration with one identifier, so every result can be traced to what produced it.
Each instruction is a test condition: write one case where following it is required and one where an ordinary user makes it hard to follow. Partitions, boundaries and decision rules from test design still apply.
- The system prompt: role, scope, rules, tone and output format.
- The template and its variables, such as
{customer_name}, filled at run time — test them empty, very long and in other scripts. - Few-shot examples, the sample inputs and ideal answers written into the prompt to show what is expected: changing or reordering them is a prompt change.
- The model identifier and parameters such as temperature: the same text can behave differently with another model version or other settings.
Building a test set of inputs
A prompt test set is a versioned file of test cases, each with an input, the variable values and the checks every acceptable answer must pass. It is testware: reviewed, stored in the repository and changed on purpose. Keep a held-out part used only to accept a version; a prompt tuned until it passes its own acceptance cases looks better on paper than it is.
Draw the cases from several sources. The excerpt below is YAML for readability; teams often store the same structure as JSON Lines.
- Instructions: a case that follows each one and a case that puts it under pressure.
- Real requests: frequent intents from logs or support tickets, with personal data removed.
- Variation: formal and informal wording, typos, Arabic, Hindi and mixed scripts, very short and very long inputs.
- Out of scope: questions the assistant must decline or redirect.
- Critical cases: safety, privacy and hand-off rules that must pass every time.
- Past failures: every prompt defect you fix becomes a case.
# support-set v7: 3 of its 40 cases
- id: DEL-004
input: "متى يصل طلبي رقم 5521؟"
vars: { order_status: shipped }
checks: [valid_json, language_is_ar, mentions_order_5521]
- id: CMP-002
input: "मेरी केतली टूटी हुई आई है"
checks: [valid_json, language_is_hi, handoff_is_true]
critical: true
- id: OOS-001
input: "Can you book me a flight to Riyadh?"
checks: [valid_json, declines_politely, no_invented_service]Try it: JSON Lines Validator Try it: Multilingual Test Data Generator Try it: Unicode Dataset Generator
Versioning prompts
A prompt that can be edited in place with no record, for example in an admin screen, cannot be tested reliably: nobody can say which text produced which answer. Keep each prompt as a file in version control, change it through review, and give every released version an identifier that the application logs with each response.
Record each accepted version with the conditions it was tested under: model identifier, parameters, test set version, date and results. A provider’s model update or a new temperature is a new configuration that needs a new run, even if the prompt text is unchanged.
- One change per version, with its reason: "v4: keep answers under 60 words; customers found replies too long".
- Never edit an accepted version in place; create the next one, so a rollback is just a switch to the previous identifier.
- Diff the two versions before testing to see which instructions changed and which cases should be affected.
Prompt regression: compare with the baseline, case by case
A prompt regression is a case that passed with the accepted version and fails with the new one. You find it by comparing the candidate with the baseline: the stored results of the last accepted version on the same test set, model and parameters. Only an accepted version’s results become the new baseline. Change only the prompt; if the model changes too, you cannot tell which change caused a difference.
Run every case. Re-running the cases that failed because of the problem the change is meant to fix is confirmation testing; re-running all the others is regression testing, and you need both. Run each case several times with a pass rule agreed in advance, then sort it into one of four groups:
- Fixed: failed with the baseline, passes now — the intended improvement.
- Regressed: passed before, fails now. A regression in a critical case blocks the change; any other needs investigation and the team’s explicit acceptance.
- Still failing: failed with both — a known problem this change did not cause.
- Unchanged pass: passed with both. Still read a sample side by side; tone or content can drift while the checks pass.
- 1Change the promptOne change, a new version identifier and the reason
support-reply v4 - 2Hold everything elseSame test set version, pinned model, same parameters
- 3Run the whole test setEvery case, several runs each, the pass rule agreed in advance
support-set v7 - 4Compare with the baselineCase by case: fixed, regressed, still failing, unchanged pass
Branch: Critical case fails or a regression is not accepted: revise the prompt and re-run the whole setFail
Gate: No critical failure; every regression understood and accepted
- 5Accept and tag the versionIts results become the new baseline; the version is logged with every responsePass
Then:The next change is compared with this baseline
Worked example: a shorter answer that broke two cases
Version v3 of the support assistant’s prompt is the baseline. Customers found its answers too long, so v4 adds: "Keep every answer under 60 words." Both versions run support-set v7 (40 cases) on the same pinned model, 5 runs per case; a case passes when all its checks pass in at least 4 runs, and critical cases in all 5.
Passing cases rise from 34 to 37, which looks like an improvement. Case by case, five verbosity cases are fixed, but RET-012 now drops the 30-day return condition, and the critical case CMP-002 fails to hand a damaged-item complaint to a person in 2 of 5 runs; a text diff of the two RET-012 answers shows the missing sentence. The critical regression blocks v4. The team writes v5 — "Keep every answer under 60 words, but always state policy conditions and never skip a hand-off" — and runs the whole set again.
Prompt: support-reply Baseline: v3 Candidate: v4 Model: pinned, unchanged
Test set: support-set v7 (40 cases), 5 runs per case
Pass rule: all checks pass in >= 4 of 5 runs; critical cases need 5 of 5
n/5 = number of runs in which all checks passed
Case Group v3 (baseline) v4 (candidate) Result
LEN-002 verbosity fail 1/5 pass 5/5 fixed
LEN-005 verbosity fail 2/5 pass 5/5 fixed
(3 more verbosity cases fixed the same way)
RET-012 returns pass 5/5 fail 2/5 regressed
CMP-002 critical pass 5/5 fail 3/5 regressed: blocks v4
LNG-004 language fail 3/5 fail 3/5 still failing (known)
(32 other cases pass with both versions)
Passing cases 34 / 40 37 / 40Common mistakes
- Editing the production prompt directly, without a new version and without a test run.
- Testing only with the examples used while writing the prompt, or accepting it on the cases it was tuned on.
- Accepting a change because the total pass rate rose, without checking which cases now fail.
- Changing the prompt and the model or its parameters at once, so a difference cannot be traced to its cause.
- Re-running only the cases the change was meant to fix: confirmation testing without regression testing.
- Judging a non-deterministic case on one run, or filing a defect without the prompt version, model and input.
The QA perspective
Join before the prompt ships: review it like a requirement (is every instruction testable, do any conflict, what happens out of scope?) and agree the pass rule and the critical cases with the developer and the product owner before anyone sees results, so nobody moves the goalposts to fit the numbers.
Build the test set with people who know the domain; support staff know what customers really ask. For each change, record the baseline and candidate versions, model, parameters, test set version, runs per case, case-by-case results and the decision. A defect report needs the prompt version, the model identifier, the exact input and output, and how often it fails ("3 of 5 runs").
Practice exercise
Decide whether a prompt change can be released
A meeting-notes assistant summarises meeting transcripts. Version v3 of its prompt adds the instruction shown below to make action items easier to follow. The table gives the test set results for the baseline v2 and the candidate v3 on the same pinned model.
Classify every case, decide whether v3 can be accepted, and say what happens next.
Prompt: meeting-summary Baseline: v2 Candidate: v3 Model: pinned, unchanged
Change in v3: "List every action item as: owner - task - due date."
Test set: meetings v2 (12 cases), 5 runs per case
Pass rule: all checks pass in >= 4 of 5 runs; critical cases need 5 of 5
n/5 = number of runs in which all checks passed
Case Critical Check v2 v3
MS-01 no summary is at most 120 words 5/5 5/5
MS-02 no every action item names an owner 2/5 5/5
MS-03 no every action item has a due date 1/5 4/5
MS-04 yes no salary figure from the HR transcript 5/5 4/5
MS-05 no an Arabic meeting is summarised in Arabic 5/5 3/5
MS-06 no no action items invented when none agreed 5/5 2/5
MS-07 to MS-12 all checks 5/5 5/5- Apply the pass rule to each case in both versions and count the passing cases.
- Put every case into one group: fixed, regressed, still failing or unchanged pass.
- Decide whether v3 is accepted, and why.
- Propose a fix and one test case the set is missing.
Show the model answer
v2 passes 10 of 12 (MS-02 and MS-03 fail); v3 passes 9 of 12 (MS-04, MS-05 and MS-06 fail).
Fixed: MS-02 and MS-03 (the latter only at the threshold, 4 of 5, so watch it). Regressed: MS-04, MS-05 and MS-06. Unchanged pass: MS-01 and MS-07 to MS-12. No case is still failing.
Reject v3. MS-04 is critical and needs 5 of 5, so one run that repeats a salary figure blocks the release on its own — a privacy defect to report with that run’s output. MS-05 and MS-06 show a typical side effect of a format instruction: the model fills the template even when it should not, inventing action items, and the English labels probably pull the Arabic summary into English, a cause to confirm by reading the outputs.
Write v4 with explicit exceptions ("If no action items were agreed, write: No action items. Use the language of the meeting.") and an explicit rule that salary figures and other personal HR details never appear in a summary, then run the whole set again; v4 can be accepted only if MS-04 passes 5 of 5. A missing case: an action item agreed without a due date, where the expected result is "due date: not set" rather than an invented date.
Frequently asked questions
Is prompt testing the same as prompt engineering?
No. Prompt engineering is writing and improving the prompt; prompt testing is gathering evidence that a given version meets agreed criteria and does not break what worked before. The same person can do both, but a prompt should not be accepted on the cases that were used to tune it.
How many cases does a prompt test set need?
There is no fixed number. Start with cases that cover every instruction, the most frequent real requests, the critical rules and the failures you have already seen, then add a case each time a new failure is found. The practical limit is the time and cost of running every case several times on each change.
Do I need to re-run the test set when only the model changes?
Yes. The model, its version and its parameters are part of the configuration under test, so the same prompt text can behave differently after a model update. Pin the model version, and treat a provider’s update as a change that needs a full run against the baseline.
Can a language model write my test inputs?
It can draft variations — paraphrases, typos, other languages — and that saves time. Review every generated input before it enters the set and write the checks yourself. If a model also grades the answers, use a different model from the one under test and compare its grades with human review on a sample.
References
- Define success criteria and build evaluationsA model provider's guidance on writing measurable success criteria and evaluation sets graded by code, by exact match or by a model.
- Working with evalsA model provider's guidance on testing model outputs against defined criteria and datasets, and re-running evals as prompts and models change.
- ISTQB Certified Tester Foundation Level (CTFL) v4.0The foundation syllabus of software testing: test levels and types, test design techniques, test management and tools.
Practise with Mutqan tools
Compare two texts line by line or word by word and highlight differences.
Validate every line of a JSON Lines file and report the exact failing lines.
Generate the same records in multiple languages (English, Arabic, Hindi, and more) to test i18n and RTL/LTR mixing.
Generate Unicode test strings across scripts (Arabic, Devanagari, CJK, Cyrillic), emoji, combining marks and normalisation forms.
Compare two JSON documents semantically and highlight added, removed and changed values.
Validate a JSON document against a JSON Schema (draft-07 / 2019-09 / 2020-12 core keywords).
Go deeper
- LLM Testing: How to Test LLM ApplicationsPrompt testing
- LLM Testing: How to Test LLM ApplicationsRegression evaluation on every prompt and model change
- LLM Evaluation: How to Evaluate LLM OutputsStep 2: build the evaluation dataset
- LLM Evaluation: How to Evaluate LLM OutputsStep 6: compare with the baseline on every change
Your progress on this topic
Not started
Mark the topic complete when you have studied it and done the exercise.
Sign in to track your progress
Mark topics complete, continue where you left off and unlock specialisation exams.