How should you name a unit test so its failure explains itself in a report?
answer
- Written for someone reading a red list
- Three parts in every good name
- Behaviour, condition, expected outcome
- Name the rule, not the fixture value
- An and in the name means split it
basics
~20 sName a unit test for the reader of a red report, who sees only the name: state the unit or behaviour under test, the condition it is in, and the outcome expected. A name needing the word and usually means the test checks two things.
solid answer
~50 sThe audience for a test name is someone reading a list of failures with no code open, so the name has to carry the whole claim. The convention that works is three parts — the behaviour under test, the condition or input state, and the expected outcome — written in the vocabulary of the domain rather than of the code: `renewal_with_expired_card_is_marked_past_due` rather than `testRenewal3`. Two rules keep it honest. First, name the *rule*, not the sample data: a name that says `amount_1499` goes stale the moment someone edits the fixture value. Second, name the promised behaviour, not the mechanism used to fulfil it, so a refactor that changes how the result is produced does not falsify every name in the file. If a name needs an 'and', that is a signal to split the test.
code
pseudocode · 12 lines// unhelpful in a failure list
test testRenewal3:
...
// carries the whole claim
test renewal_with_expired_card_is_marked_past_due:
...
// grouping gets the same triple
group renewal_of_an_active_subscription:
test with_an_expired_card_it_is_marked_past_due:
...go deeper
Learn the three-part shape and use it every time: what is under test, under which condition, with which expected outcome. Avoid numbered names and avoid the words works or correct in a test name.
Be able to explain who reads the name and when, and to critique a bad name concretely rather than by taste. Know why naming the fixture value or the mechanism creates maintenance you will pay for later.
Demonstrate that you treat the whole failure report as the artefact: name plus assertion message, diagnosable without opening the file. Show how you catch drift between naming conventions in review rather than by rewriting a suite later.
Own the convention itself: one style per codebase, written down, enforced lightly, and chosen for what it costs a reader during an incident rather than for elegance. Be ready to justify the triage time saved when someone calls naming rules bikeshedding.
## Who the name is written for A test name is read at its least convenient moment: a build has gone red, someone is scanning a list of forty lines of output, and the code is not open. That reader has to decide, from the name alone, whether the failure is theirs and roughly what broke. Every naming rule below follows from that one fact — the name is a **failure report**, not a label. This is also why 'the code is right there, just open it' is a weak defence. It is true and it is expensive: multiplied across a suite, unreadable names convert a five-second triage into a five-minute one, and the cost lands on whoever is least equipped to pay it. ## The three parts Almost every workable convention encodes the same triple: 1. **the behaviour or unit under test** — what is being exercised, 2. **the condition** — the state or input that makes this case distinct, 3. **the expected outcome** — the promise being checked. ```pseudocode renewal_with_expired_card_is_marked_past_due renewal_on_the_final_day_of_the_term_still_charges renewal_for_a_cancelled_subscription_makes_no_charge ``` Read any of those aloud and you have a sentence a product person would recognise. Compare the failures they replace: ```pseudocode testRenewal3 testRenewalWorks shouldWork testCase_2b ``` A nesting or grouping structure — a named container per behaviour, with cases inside it — is an equally good way to get the triple, because most reporters print the container path alongside the case name. What matters is that the concatenation reads as a claim, not that all three parts sit in one identifier. ## Four naming failures worth recognising **Naming the data instead of the rule.** `renewal_of_a_29_99_plan_succeeds` pins a fixture value into the name. Change the fixture and the name lies; and it never told the reader *why* that number was chosen. Name the property the number stands for — `renewal_below_the_review_threshold_is_auto_approved`. **Naming the mechanism instead of the promise.** A name that describes how the code reaches the outcome ties the report to a structure that a refactor is allowed to change. Names should survive any change that preserves observable behaviour; if a pure restructuring forces a rename sweep, the names were describing the wrong layer. **Numbered and vacuous names.** `test1`, `testHappyPath`, `worksCorrectly`. These are what a suite looks like when names were treated as required syntax rather than as output. 'Works correctly' is exactly the claim under dispute when the test is red. **Compound names.** `renewal_charges_and_sends_an_email_and_updates_the_ledger` cannot fail informatively: whichever assertion trips, the name over-promises, and the first failure hides the rest. The name is diagnosing a structural problem — the test has more than one reason to fail. ## The name is half of the report; the failure message is the other Even a perfect name only tells you which claim broke, not by how much. The other half is the failure message the assertion emits — the artefact that says what was expected and what was actually observed, in domain terms. A comparison that prints a whole object graph with one differing field is technically complete and practically useless; a message that names the field and the two values turns triage into reading. Where the framework's default message is opaque, supplying an explicit one is cheap and pays back on the first failure. Between a self-describing name and a self-describing message, a failure should be diagnosable from the report alone in the common case. ## Consistency beats the particular convention There are several established styles — underscore-separated triples, given-when-then phrasing, nested containers with sentence-style case names — and the arguments between them are mostly aesthetic. What is not aesthetic is mixing them. A suite where three conventions coexist forces the reader to re-learn the parsing rule per file, which is precisely the cost the naming discipline exists to avoid. Pick one per codebase, write it down, and let the review catch drift. It is also worth accepting some length: a name is read far more often than it is typed, and the cost of a long name is entirely borne by autocomplete. ## A quick self-check Before committing a test, cover the body and read only the name. If you cannot say what state was arranged and what outcome is expected, the name is not finished. If the sentence you produce needs an 'and', the test is not finished either.
- A test name contains the word and. Why is that usually a defect rather than a style issue?Because a name with an and describes two promises, and a test with two promises has two reasons to fail. Whichever assertion trips first hides the other, and the name over-claims in the report either way. Split it into two cases, each with a single condition and a single expected outcome; shared arrangement can move into a helper without merging the claims.
- Besides the name, what else has to be right for a red build to be readable without opening the code?The failure message the assertion emits. It should state the expected and the observed value in domain terms and point at the differing field, not dump a whole object graph. Name plus message together should let a reader triage from the report alone; when a framework default is opaque, an explicit message is a cheap fix that pays back on the first failure.
- Should a test name include the numeric value used in the fixture?Only when the number is itself the rule — a documented threshold or boundary. Otherwise the name pins an incidental value: it goes stale when the fixture is edited and never explains why that value was chosen. Name the property instead, such as the case being below a review threshold, so the name survives edits to the data.
saying these in an interview costs you the question
- The name does not matter, the code is right there
- Numbering tests is fine as long as they are ordered
- Names like worksCorrectly or happyPath are descriptive enough
- Long test names are bad style and should be abbreviated
- One test can cover several outcomes if the name lists them
- Names should describe how the code produces the result