Skip to content

Blog

Negative Test Cases: Examples Every QA Engineer Should Use

Learn how to design negative test cases with practical examples for validation, authorization, state conflicts, and API failures that catch real defects.

QA Workflow Assistant12 min read
  • negative-testing
  • test-cases
  • qa
  • test-design

Positive cases prove the happy path. Negative test cases prove the product refuses the wrong thing — bad input, wrong role, illegal state transition — without collapsing into a 500 page or a silent data corruption. Teams that skip negatives ship demos that work in rehearsals and fail with real users the first week after launch.

This article is a design guide with examples across UI and API. It does not replace how to write QA test cases; it specializes the "fail correctly" half of the suite. For boundaries that are weird but still valid, see edge case testing.

What counts as a negative test case?

A negative case intentionally violates a rule and expects a controlled rejection:

  • Validation failure
  • Authorization denial
  • Business rule refusal
  • Protocol misuse

It is not "click around until it breaks" (that is exploratory testing). It is a scripted expectation of failure with a specific, falsifiable outcome.

Good negative expected result: "Save blocked; inline error on End date; no API write; prior data unchanged." Weak: "Shows an error."

The difference matters at review time. The weak version passes if literally any red text appears. The good version fails loudly if the record silently saved anyway behind a misleading toast — which is exactly the class of bug negatives exist to catch.

Why negatives pay for themselves

Teams that treat negative cases as filler tend to under-resource them, then discover the cost later in support tickets and incident reviews.

BenefitExample
Prevents bad dataEnd date before start date never persists
Protects authzViewer cannot delete invoices
Clarifies UXUsers understand what to fix
Documents rulesCases become living spec for edge policies
Supports auditsEvidence of access denial testing
Reduces support loadA clear inline error beats a confused ticket about "it just disappeared"

The last row is easy to underrate. A well-worded validation error can eliminate an entire category of support contact. Negatives are not only a defect-prevention tool; they are a documentation tool for rules nobody wrote down anywhere else.

Categories of negative cases

1. Input validation

Empty required fields, wrong types, over-long strings, invalid enums, malformed emails, negative quantities where not allowed.

2. Authorization and tenancy

Authenticated but forbidden; cross-tenant IDOR attempts; CSRF on cookie apps.

3. State conflicts

Cancel an already-cancelled order; submit a form twice; edit a deleted entity; approve after a rejection reached a terminal state.

4. Dependency failures

Payment decline; upstream 503; webhook signature invalid — see also API test cases and payment-specific suites.

5. Protocol / client misuse

Wrong content-type; missing auth header; unsupported HTTP method.

Example set: subscription cancellation form (UI)

Assume a billing settings page where a customer can cancel a paid subscription, with a required "reason" dropdown and an optional feedback text field.

  1. Submit cancel with no reason selected → blocked, field error, no cancellation request sent.
  2. Cancel an already-cancelled subscription (second tab, stale page) → blocked with a "already cancelled" message, not a duplicate cancellation event.
  3. Cancel while a payment dispute is open on the account → blocked or routed to support per policy, not silently processed.
  4. Non-owner team member without billing permission opens the cancel URL directly → denied; no cancel control rendered, and the underlying API call rejected even if the button were forced via devtools.
  5. Feedback text field receives a script tag → stored encoded or rejected; internal admin dashboard does not execute it when a support agent views the reason.
  6. Network drops mid-submit → user sees a retryable error, not a false "subscription cancelled" confirmation while the backend never received the request.
  7. Double-click the cancel confirmation button → exactly one cancellation event, not two support emails and two proration calculations.

Each of these is a separate case. Bundling them into one "test cancel flow" case hides which specific rule broke when something regresses.

Example set: bulk CSV import API (HTTP)

Assume an endpoint that accepts a CSV upload to bulk-create customer records.

POST /v1/imports/customers HTTP/1.1
Authorization: Bearer {{editor_token}}
Content-Type: multipart/form-data; boundary=----abc
 
------abc
Content-Disposition: form-data; name="file"; filename="customers.csv"
 
email,name
not-an-email,Jane Doe
------abc--

Expect: 422 with a row-level error report identifying line 2; zero rows committed from that file (no partial import), since a half-committed batch is often worse than a full rejection.

Additional negatives for the same endpoint:

RequestExpect
Viewer-role token attempts import403, no rows processed
File exceeds size limit413 or documented equivalent, clear message
Duplicate emails within the same fileDocumented dedupe or rejection rule, not silent last-write-wins
Re-upload the identical file twiceDocumented idempotency behavior — reject, skip, or create duplicates on purpose
Malformed CSV (unclosed quote)400 with a parse error, not a 500 stack trace

Bulk operations are a rich source of negative cases because a single bad row can either poison the whole batch or get silently dropped — both outcomes need an explicit, tested rule.

Designing negatives from requirements

Translate acceptance criteria line by line instead of guessing at coverage after the fact:

"Only owners can archive a workspace."

becomes:

  • Owner archives → positive
  • Member archives → negative 403
  • Owner archives an already-archived workspace → state negative
  • Owner archives a workspace with an active trial → check whether that is even allowed, and if not, add the refusal case

"Invitations expire after 7 days."

becomes:

  • Accept invite on day 6 → positive
  • Accept invite on day 8 → negative, expired message, no account created
  • Accept invite twice with the same link → second attempt is a state negative, not a duplicate account

If criteria never mention failure at all, ask product for the rule before writing a case that guesses at behavior. Unstated negatives become production incidents, and a guessed expected result is worse than no case — it teaches the team the wrong thing passed review.

Negative testing for third-party integrations

Negatives are not limited to your own UI and API. Anything your product depends on can misbehave, and the dependency's failure mode is part of your contract with the user.

DependencyNegative scenarioExpect
SSO identity providerIdP returns an error responseLocal session not created; actionable error shown
Webhook senderSignature header missing or invalid401/400; event not processed
Search indexIndex temporarily unavailableDegraded search message, not a blank crash
Email providerProvider returns a hard bounceInternal state reflects delivery failure, not "sent"
Feature-flag serviceFlag service times outDocumented safe default, not an undefined UI state

Treat each of these as first-class negative cases rather than "infrastructure problems we'll deal with if they happen." They happen.

Severity and priority heuristics

PatternTypical priority
Authz bypass riskHigh
Data corruption riskHigh
Payment or billing state left ambiguousHigh
Annoying validation UXMedium
Rare protocol misuseLow/Medium

Do not mark every negative High or the suite loses signal. A prioritized list tells a release manager where to look first when time is short; a flat list of all-High cases tells them nothing.

Negative vs edge vs chaos

TypeIntent
NegativeInvalid or forbidden
EdgeValid but extreme (see the edge case article)
ChaosInfrastructure fault injection

Keep naming honest so managers do not think the team "did chaos testing" when they only emptied a required field. Conflating the three makes coverage claims in status reports misleading, even unintentionally.

Mapping common HTTP outcomes to negative intent

A quick reference for API-adjacent negatives, useful when a team argues over which status code a new refusal should return:

SituationTypical statusNote
Not authenticated401Client should know to re-auth
Authenticated, not permitted403Distinct from 401 in most designs
Resource does not exist (or hidden for tenancy)404Some teams deliberately use 404 instead of 403 to avoid confirming existence
Valid auth, invalid payload400/422Field-level detail helps clients
Valid request, conflicting state409Cancel-twice, duplicate-slug style conflicts
Rate limited429Include retry guidance when possible

Test the codes your API actually documents. This table is a starting vocabulary, not a mandate to implement every code regardless of whether your framework or gateway supports it cleanly.

Data and fixture strategy

Negatives need a known-good baseline so you can prove nothing changed:

  1. Capture the before state (API GET or a DB seed snapshot).
  2. Perform the illegal action.
  3. Assert the error.
  4. Re-read the before state — confirm it is unchanged.

Without step 4, you have only tested that an error string appeared, not that the system actually refused to act. Plenty of real bugs show a friendly error toast while still writing bad data underneath it.

Automation guidance

Automate stable negatives early — they are excellent CI guards against silent regressions. Avoid automating every typo variant of the same validator; parameterize instead.

// illustrative
for (const name of ["", "ab", "x".repeat(81)]) {
  await expect(updateProject({ name })).rejects.toMatchObject({ status: 422 });
}
 
// state-conflict style negative
const sub = await cancelSubscription(subId);
expect(sub.status).toBe("cancelled");
await expect(cancelSubscription(subId)).rejects.toMatchObject({ status: 409 });

UI doubles for critical authz screens are worth keeping even after API coverage exists, since a client-side bug can expose controls the server would correctly reject — a confusing experience even if no data is actually at risk.

Common mistakes with negative suites

  1. Only UI validation — the server accepts what the UI blocks, so anyone bypassing the UI (a script, a mobile client, a future integration) slips through.
  2. No persistence check — an error toast appears after the data already wrote.
  3. Message matching too brittle — assert error codes or stable identifiers when possible, not exact copy that marketing will rewrite next quarter.
  4. Punishing users with jargon — UX review still matters on negatives; "Error 4471" helps nobody.
  5. Duplicates — forty email-format variants that all exercise the same regex teach the suite nothing new after the second one.

Building a negative pack for a feature launch

Minimum pack for a new feature:

  • Required field empties
  • One boundary violation on each side of a limit
  • One wrong-role attempt
  • One illegal state transition
  • One dependency failure message path
Rule from acceptance criteriaPositive caseNegative case(s)
"Only admins can invite"Admin invites successfullyMember invites → 403
"Invite expires in 7 days"Accept on day 6Accept on day 8 → expired
"Email must be unique per workspace"New unique email invitedDuplicate email invited → conflict

A short matrix like this, kept next to the story, is often more useful during review than a long prose description of "edge cases considered."

Expand this minimum pack for regulated or multi-tenant systems where a missed authz negative has compliance consequences, not just a bad support ticket. Depth choices are covered in Basic / Standard / Deep. Story conversion: Jira story → workflow. Plans: Pricing. Setup: Docs.

FAQ

Are negatives the same as security testing?

Overlapping, not identical. Security testing includes threat modeling and offensive techniques. Negatives are structured functional refusals — including many security-relevant ones like authz denials.

How many negatives are enough?

Enough to cover each rule once, plus high-risk bypass attempts. Volume without new rules being exercised is waste, not coverage.

Should we test every HTTP 4xx code?

Test the codes your API actually emits for real client mistakes. Do not invent a matrix of unused statuses just to look thorough in a report.

Do exploratory sessions replace negatives?

They discover candidates. Script the ones worth keeping so the next release does not have to rediscover them from scratch.

How do negatives fit into a regression suite?

Promote the negatives tied to your highest-risk rules — authz, payment, and data-integrity refusals — into your durable regression test cases core, and leave the rare protocol-misuse variants in an extended or exploratory pack.

Final checklist

  • Each business rule has at least one refusal case
  • Authz negatives exist for sensitive actions
  • Persistence verified unchanged after rejection
  • API and UI enforcement both considered
  • Error expectations are specific
  • Priority reflects risk, not drama
  • Parameterize redundant input variants
  • State-conflict cases included
  • Dependency and third-party failures have UX/API expectations
  • Naming distinguishes negative vs edge

CTA — mine stories for refusal rules

When acceptance criteria only describe success, ask what must not happen — then draft those negatives in QA Workflow Assistant alongside positives so review boards see both sides before sign-off. Keep authorization wording reviewed by engineering leads. Environment setup stays in Docs.