Sharajdev

How to Write Negative & Edge-Case Test Cases (50 Examples)

The happy path is the part of a feature that someone already tested by building it. Bugs that reach production usually come from the paths nobody wrote down: empty input, the double click, the dropped connection, the name with an apostrophe. This guide covers how to find those cases systematically, then gives you 50 you can adapt today.

By Sharaj Rewoo · Updated 25 September 2026

Negative vs. edge cases: what's the difference?

The two terms get used interchangeably, but they answer different questions:

A good suite has both. Negative cases protect data and security; edge cases catch off-by-one errors, rounding, and layout that only breaks at the extremes.

Four techniques that find them for you

You don't need inspiration to find edge cases. You need a method. These four cover most of what experienced testers do by instinct.

1. Equivalence partitioning

Split every input into groups the system should treat the same way, then test one value from each group. For an age field accepting 18–65, the partitions are: below 18, 18–65, above 65, and not a number at all. Four tests cover what a hundred random values would. The negative cases fall out naturally: every partition outside the valid range is one.

2. Boundary value analysis

Defects cluster at the edges of partitions, because that's where someone typed < when they meant <=. For each boundary, test the value just below, on, and just above it. For 18–65, that's 17, 18, 19, 64, 65 and 66. Apply the same thinking to lengths (0, 1, max−1, max, max+1 characters), counts, dates and file sizes.

3. Error guessing

This is experience written down. Some inputs break software so often they're worth trying on every field: empty strings, whitespace only, very long strings, emoji, ' and ", <script>, leading zeros, negative numbers, null-looking text such as the word "null". Keep a personal list and grow it every time a bug surprises you.

4. State transition testing

Many bugs aren't about the input but about when it arrives. Draw the states an object can be in (draft, submitted, approved, cancelled) and the actions that move between them. Then test the transitions that should be impossible: approving a cancelled order, editing after submission, going back after payment. Every arrow that isn't on the diagram is a negative test.

Worked example: one user story, twelve cases

Here is a typical story:

"As a user, I can apply a discount code at checkout so that the discount is taken off my order total. Codes are 6–12 alphanumeric characters, can be used once per account, and expire on a set date."

The happy path is one test: enter a valid code, see the reduced total. Applying the four techniques gives far more:

That's a dozen meaningful cases from four sentences, and each one is a place where real checkout systems have shipped bugs. If you do this for every story, it gets repetitive quickly, which is exactly why QAtalyst exists: paste the story and it drafts positive, negative, edge and boundary scenarios for you to review and refine.

50 negative and edge-case test cases

Adapt these to your feature. Each one names the condition and the result you should expect.

Input validation

  1. Submit a required field left empty. Expect: inline error on that field, form not submitted.
  2. Submit a field containing only spaces. Expect: treated as empty, not saved as blank text.
  3. Enter leading and trailing whitespace in an email or username. Expect: trimmed, or rejected with a clear message.
  4. Enter an email without an @ or with two. Expect: validation error, no request sent.
  5. Enter letters in a numeric field (quantity, age, price). Expect: rejected, or the field refuses the keystroke.
  6. Enter a negative number where only positives make sense. Expect: validation error, not a negative total.
  7. Enter a decimal in an integer-only field (2.5 items). Expect: rejected or rounded by a documented rule.
  8. Paste <script>alert(1)</script> into a text field that is displayed elsewhere. Expect: rendered as text, never executed.
  9. Enter a name with an apostrophe or quote (O'Brien, "Ed"). Expect: saved and displayed correctly, no server error.
  10. Upload a file with the wrong type but a renamed extension (a .exe renamed to .png). Expect: rejected based on content, not just the extension.

Boundaries and limits

  1. Enter exactly the maximum allowed length. Expect: accepted and displayed without truncation.
  2. Enter maximum length plus one. Expect: blocked or rejected with a message stating the limit.
  3. Enter exactly the minimum length, then one below. Expect: first accepted, second rejected.
  4. Upload a file exactly at the size limit, then slightly over. Expect: first succeeds, second fails with a size message rather than a timeout.
  5. Set a quantity to 0. Expect: item removed or an error, never an order line for zero.
  6. Enter the largest value the field allows (and one above). Expect: no overflow, scientific notation or rounding surprises.
  7. Use dates at month and year boundaries: 31 January + 1 month, 29 February in a leap year, 31 December. Expect: correct date arithmetic.
  8. Load a list with zero items. Expect: a helpful empty state, not a blank screen or error.
  9. Load a list with exactly one page of items, then one more. Expect: pagination appears at the right point and the last item isn't lost.
  10. Apply a discount or refund larger than the total. Expect: total floors at zero or the action is blocked.

Authentication, authorisation and sessions

  1. Log in with a correct username and wrong password. Expect: a generic error that doesn't reveal whether the account exists.
  2. Fail login repeatedly. Expect: rate limiting or lockout after the documented number of attempts.
  3. Open a page that requires login in a private window. Expect: redirect to login, then back to the original page after signing in.
  4. Change the ID in a URL to another user's record (/orders/1042 → /orders/1043). Expect: 403 or 404, never the other user's data.
  5. As a low-privilege user, call an admin-only API directly. Expect: rejected by the server, not just hidden in the UI.
  6. Let the session expire, then submit a form. Expect: prompt to log in again without losing what was typed, or a clear message.
  7. Log out, then press the browser Back button. Expect: no protected content shown from cache, and actions fail.
  8. Change your password in one browser while logged in on another. Expect: the other session is signed out, if that's the documented policy.

Concurrency and timing

  1. Double-click a Submit or Pay button. Expect: exactly one order or charge.
  2. Open the same record in two tabs, edit and save both. Expect: a conflict warning or a defined last-write rule, never silent data loss.
  3. Two users claim the last item in stock at the same moment. Expect: one succeeds, the other gets a clear out-of-stock message.
  4. Delete an item in one tab, then try to edit it in another. Expect: "no longer exists" message, not a crash.
  5. Refresh the page while a save is in progress. Expect: the data is either saved or not, never half-saved.
  6. Perform the action right as a scheduled job runs (e.g. at midnight when codes expire). Expect: consistent behaviour on either side of the cut-over.

Network and failure handling

  1. Go offline, then submit a form. Expect: a clear offline message and the input preserved.
  2. Make the API return a 500. Expect: a friendly error and a retry option, no raw stack trace.
  3. Make the API respond slowly (10+ seconds). Expect: a loading state, a timeout message, and no duplicate submissions.
  4. Return an empty or malformed JSON body. Expect: the UI handles it without a blank screen.
  5. Return a response with a missing optional field or an unexpected null. Expect: the UI shows a fallback, not "undefined".
  6. Fail a third-party dependency (payment provider, maps, analytics). Expect: core flows keep working, or fail with a clear message.

Cases 36–39 are hard to reproduce against a real backend. You can force them in the browser by mocking the response; see how to mock API responses in Chrome for four ways to do it, including Mockingbird, which can hold, delay or stand in for any request in a tab.

Internationalisation and data

  1. Enter names with accents, Chinese or Arabic characters, and emoji. Expect: stored and displayed exactly as typed.
  2. Switch to a right-to-left language. Expect: layout mirrors correctly and nothing overlaps.
  3. Switch to German or Finnish, where words are long. Expect: labels wrap or fit; buttons don't clip text.
  4. Change the locale to one using a comma as decimal separator. Expect: prices and inputs parse and display correctly.
  5. Use a user in a different time zone, especially across a date line. Expect: dates and deadlines show the correct day.

Localization defects are tedious to check by eye across many pages. LingoAI audits a page against a target locale and flags untranslated strings, clipped UI and leaked placeholders such as {name}.

UI state and navigation

  1. Use the browser Back button in the middle of a multi-step flow. Expect: the previous step with data intact, no duplicate submission.
  2. Bookmark or share a URL from step 3 of a wizard and open it fresh. Expect: redirect to a valid starting point, not a broken page.
  3. Resize the window to mobile width mid-task. Expect: layout adapts and input is kept.
  4. Complete the flow using only the keyboard. Expect: every control reachable, visible focus, no keyboard traps.
  5. Fill the form with browser autofill or a password manager instead of typing. Expect: validation still runs and the autofilled values are accepted.

How to keep these from becoming a checklist nobody reads

Related