Skip to content
Bugwise
Menu
Testing Fundamentals

Equivalence Partitioning

You can't test every possible value, so don't try. Learn to split inputs and outputs into groups that behave the same, test one value from each, and catch more bugs with far fewer tests.

beginner Mobile & web
Short on time? Switch to the quick version.

You’re testing the sign-up screen of a fitness app. The requirement is one line long: “Users must be 18 to 60 years old.” There’s an Age field and a Continue button.

So you type 18. It works. You type 19. Works. 20, 21, 22… After ten minutes you’ve typed 43 ages and you haven’t even tried 0, -5, 150, “abc”, 25.5 or leaving the field empty. And this is one field on one screen.

There has to be a smarter way. There is, and it’s called equivalence partitioningEquivalence partitioningSplitting inputs into groups that should behave the same, then testing one value from each group.Open in glossary → (EP). It’s the first test design technique most testers learn, and you’ll use it every single day.

Why you can’t test every value

Even a tiny field accepts a huge number of possible inputs: every whole number, every decimal, negative numbers, letters, emoji, spaces, pasted text, nothing at all. Multiply that by every other field on the form and every phone and browser, and you get more combinations than anyone could run in a lifetime.

This is one of the seven testing principles from What Is Software Testing?: exhaustive testing is impossible. The real skill is choosing a small set of tests that still finds the bugs. EP is the tool for exactly that.

The big idea: values that behave the same

An equivalence partition (also called an equivalence class) is a group of values that the software should treat in exactly the same way. If one value in the group works, the others should too. If one fails, the others probably fail the same way.

That gives us the core rule of EP:

Split the possible values into partitions, then test one representative value from each partition.

For our fitness app, the age rule creates three partitions on the number line:

Age field · fitness app sign-up (18–60)

≤ 17

Too young · rejected

18 – 60

Accepted

≥ 61

Too old · rejected

Three partitions on the line, so three tests: for example 12, 35 and 72. Testing 36 as well adds nothing new, because it's in the same partition as 35.

EP is a black-boxBlack-box testingTesting based only on inputs and outputs, without looking at the code.Open in glossary → technique: you derive tests from the requirement, not from the code. You don’t need to know how the app was built, only how it should behave.

The quick version

Valid and invalid partitions

Some partitions can’t be drawn on a number line at all, and they’re where many real bugs hide:

  • Empty: the user leaves Age blank.
  • Not a number: “abc” pasted into the field.
  • Wrong kind of number: 25.5 when the rule says whole years.

So the age field really has six partitions, and EP gives you six tests: 12, 35, 72, empty, “abc”, 25.5.

Where partitions hide

What you’re testingExamplePartitions
A number rangeCart quantity 1–100 or less · 1–10 · 11+
Text lengthPromo code 6–10 charsempty · 1–5 · 6–10 · 11+
A set of optionsPayment methodeach option behaves differently
A formatEmailvalid · missing @ · missing domain…
An outputShipping by order total€4.99 · €2.99 · free

How many tests?

At least one per partition. Then use one rule to keep things clear:

  • Valid partitions can share a test. One sign-up with a valid age, a valid email and a valid country covers three valid partitions at once.
  • Invalid partitions get a test each. If you enter age 15 and a broken email together, the app may only complain about the email, and you never find out whether age 15 is rejected.

Three classic mistakes

  1. Forgetting the empty partition. “Nothing typed” is a value too, and a favorite crash.
  2. Mixing partitions. Overlapping groups (“0–18” and “18–60” both contain 18), or several invalid values in one test.
  3. Forgetting non-numeric input in number fields. A number keyboard doesn’t stop paste, autofill or someone calling the APIAPIThe way different software parts talk to each other, like an app asking a server for data.Open in glossary → directly.

Doing EP step by step

Here’s the process you’ll follow every time, using the fitness app’s age field.

  1. Find the input (or output) and its rule. “Age: whole years from 18 to 60.”
  2. Find where the behavior changes. Below 18 the app rejects you; from 18 it accepts; from 61 it rejects again. Those change points split the line into partitions.
  3. Add the partitions that aren’t on the line. Empty field, non-numeric text, decimals. Ask: “What else could a user (or a bug) send here?”
  4. Label each partition valid or invalid. Valid = should be accepted. Invalid = should be rejected with a helpful message.
  5. Pick one representative value per partition. Something clearly inside it: 35 rather than 18. (The edges get their own technique; more on that below.)
  6. Turn them into test cases, combining valid partitions and keeping invalid ones separate. See How to Write Test Cases for the format.

The result for the age field:

PartitionTypeTest valueExpected
18 to 60Valid35Accepted
17 or lessInvalid12“You must be at least 18”
61 or moreInvalid72“This plan is for ages 18 to 60”
EmptyInvalid(blank)“Enter your age”
Not a numberInvalidabc“Age must be a number”
DecimalInvalid25.5“Enter whole years”

Six tests instead of hundreds, and each one checks something genuinely different.

Valid and invalid partitions

A valid partition contains values the system should accept and process normally. Testing these is positive testingPositive testingTesting with valid input to confirm the software works as expected.Open in glossary →: “does it work when used correctly?”

An invalid partition contains values the system should refuse, ideally with a clear, friendly error messageError messageText that tells the user something went wrong and, ideally, how to fix it.Open in glossary →. Testing these is negative testingNegative testingTesting with invalid or unexpected input to check the software handles it gracefully.Open in glossary →: “does it fail gracefully when used incorrectly?”

There can be more than one valid partition too. That happens whenever the app does something different for different valid values, like the cinema’s child, adult and senior prices. All three are valid, but each gives a different result, so each needs its own test.

Where partitions hide

Partitions aren’t just for number fields. Once you start looking, you’ll see them everywhere.

Numbers and ranges

The classic case: a minimum, a maximum, and everything in between. In a shop’s cart, the quantity of one item must be 1 to 10.

Cart quantity (1–10)

≤ 0

Error

1 – 10

Cart updates

≥ 11

"Max 10 per order"

Plus the off-the-line partitions: empty (the user deletes the number and taps away: does the cart show 0, NaN, or the old value?), decimals (2.5 socks) and text. See the shopping cart and checkout lesson for more cart traps.

Some rules have only one limit: “withdraw at least €10” has a valid partition (€10 and up) and one invalid partition (under €10), plus empty and non-numeric.

Text length

For text fields, the “number” is the length. A food delivery app’s promo code field is optional, but a filled-in code must be 6 to 10 characters:

Promo code length (optional, 6–10 characters)

0

No code · OK

1 – 5

Too short

6 – 10

Format OK

≥ 11

Too long

Because the field is optional, empty is a VALID partition here. In a required field, the same empty value would be invalid. Same value, different rule, different partition.

Text also has content partitions: letters only, digits, symbols (“SAVE-10!”), spaces at the start or end, upper vs lower case, diacriticsDiacriticsAccent marks on letters, like é, ü, č or ž. Search usually should ignore them.Open in glossary → (é, ö, ž) and emoji. Each one is worth a thought: “should this behave differently?” The text field page goes deeper.

Sets of options

When the input is a choice from a list, each option that leads to different behavior is its own partition. Options that behave identically can share one.

InputPartitionsWhy
Payment methodCard · PayPal · Apple Pay / Google Pay · Pay on deliveryEach one runs a different flow (3-D Secure, redirect, wallet sheet, no payment step)
Shipping country (EU shop)Home country · other EU country · non-EU country · no country chosenDifferent shipping prices, VAT and customs rules
Country list for the phone prefixOne country per format group, not 195 countriesCountries with the same number format behave the same

You would not test all 195 countries in a dropdown. You’d ask the team which countries are treated differently (different tax, currency, address format, delivery rules) and pick one from each group. Don’t forget the invalid partition: nothing selected.

Formats

Some inputs are valid only in a certain shape. The best-known example is email:

PartitionExampleExpected
Valid formatanna@shop.comAccepted
Missing @anna.shop.com“Enter a valid email”
Missing domainanna@“Enter a valid email”
Space insideanna @shop.com“Enter a valid email”
Empty(blank)“Email is required”

Real email rules are surprisingly complex (plus signs like anna+promo@shop.com and long domain endings like .travel are valid), so they are good extra partitions to check against the requirement. More on this in Login and Sign-up.

The same thinking works for phone numbers, postcodes, card expiry dates (MM/YY) and IBANs.

Outputs

EP isn’t only for what the user types. You can also partition outputs: the different results the app can produce. Then you pick inputs that land you in each output partition.

A shop calculates shipping from the order total:

Shipping cost by order total (output partitions)

under €20

€4.99 shipping

€20 – 49.99

€2.99 shipping

≥ €50

Free shipping

All three are valid, but each produces a different output. Three tests: e.g. carts worth €12, €35 and €80.

Other output partitions you’ll meet: a banking app showing a balance as positive, zero or negative (overdrawn); a search returning no results, one result or many (see Search, Filters and Sorting); a fitness app’s weekly summary for “goal reached” vs “goal missed”.

How many test cases do you need?

The minimum is one test per partition. The share of partitions you’ve tested is your EP coverage: if you identified 6 partitions and tested 4, that’s 67% coverage. Aim for 100%.

But a form has several fields, and that’s where the combining rule matters.

Combine valid, isolate invalid

  • Test 1: age 35, email anna@shop.com, country Germany → account created (three valid partitions in one go)
  • Test 2: age 12, everything else valid → age error
  • Test 3: email anna@, everything else valid → email error

Several invalid values at once

  • Test 1: age 12, email anna@, country none → “Enter a valid email”

Did the app reject age 12? You can’t tell. The email error may have hidden the others.

Why does this work?

  • Valid values can be combined because, if everything passes, every partition has been shown to work. If one test fails, you investigate and split it.
  • Invalid values must be tested one at a time because of error masking: many apps stop at the first problem they find, or show only one message. A second invalid value can hide behind the first, and a real bug (age 12 being accepted) slips through.

So for a sign-up form with three fields that have 6, 5 and 3 partitions, you don’t need 6 × 5 × 3 = 90 tests. You need a few tests that cover all valid partitions together, plus one test for each invalid partition. That’s usually 10–15 tests, which you can actually run.

Common mistakes

MistakeExampleFix
Missing the empty / null partitionNever leaving Age blankAlways add “empty” (and “only spaces” for text)
Overlapping partitions“0–18” and “18–60”: where does 18 go?Partitions must not overlap, and must leave no gaps
Mixing invalid values in one testAge 12 + broken email togetherOne invalid partition per test
No non-numeric input for numbersNever typing “abc” in QuantityAdd a “not a number” partition
Splitting without a reasonTesting ages 20, 30, 40 and 50Only split where the rule behaves differently
Testing only the happy pathOnly valid partitionsInvalid partitions usually outnumber valid ones

Where EP stops and boundaries begin

EP tells you that 35 represents the whole 18–60 partition. But what if the developer typed age > 18 instead of age >= 18? Then 35 still passes and the bug survives, because the mistake lives exactly on the edge, at 18.

That’s why EP has a partner technique: Boundary Value Analysis. EP picks a value from the middle of each partition; BVA tests the edges between them. You’ll almost always use them together.

See also: Error Guessing and Checklists for the inputs no partition list mentions, like spaces only, emoji or a leap day.

Practice: build the partitions

Pick a requirement, split the number line where the behavior changes, label each partition, choose a value to test, and decide which partitions live off the line. The trainer tells you what you got right and why.

🧩 Partition builder

Split the line into partitions, label each one, pick a value to test from each, then check your work.

Fitness app · sign-up form

The "Age" field accepts whole years from 18 to 60. Anything else shows an error.

1. Split the line where the behavior changes

Click the line to add (or remove) a split. A split at X means "a new partition starts at X". Unit: years.

2. Label each partition and pick one value to test

  • All values

3. Which partitions can't be drawn on the line?

Tick the ones that are real, separate partitions for this requirement.

Test it: which partition does your value fall into?

Now be the tester. Type values into the app and watch which partition each one hits. Try to cover every partition with as few values as possible; a second value from the same partition teaches you nothing new.

🔬 Test it: which partition is this value in?

Type a value into the app and submit it. Try to hit every partition with as few values as you can.

Create account

Partitions

Covered 0/6

  • Emptye.g. (blank)
  • Not a numbere.g. abc
  • Decimale.g. 25.5
  • Below 18e.g. 12
  • 18 – 60e.g. 35
  • Above 60e.g. 72

Green = valid, red = invalid, blue = a different output.

Your turn: a small spec

A fitness app lets users set a daily step goal:

The step goal is a whole number from 1,000 to 50,000. The field is required. Users also pick a goal type: Walking, Running or Cycling. Cycling goals are measured in kilometers instead of steps, so the screen changes when Cycling is selected.

Write down the partitions for both inputs, mark each one valid or invalid, pick a test value for each, and work out the smallest set of tests that covers them all.

Show a model answer

Step goal partitions

PartitionTypeTest value
1,000 – 50,000Valid8,000
999 or lessInvalid500
50,001 or moreInvalid80,000
EmptyInvalid(blank)
Not a numberInvalid“ten”
DecimalInvalid7500.5

Goal type partitions: Walking and Running behave the same (steps), so they can share one partition; Cycling is its own partition (kilometers, different screen); and “nothing selected” is invalid if the type is required (ask!).

Tests: two valid tests (8,000 steps + Running; a valid km goal + Cycling), plus one test for each of the five invalid step-goal partitions and one for “no goal type”. That’s 8 tests. If you also tested Walking separately, that’s a reasonable extra, but EP says it adds little.

Bonus question for the team: is the 1,000–50,000 range also used for the Cycling km goal? Probably not, so Cycling may need its own range partitions.

Example test cases

TC-EP-01Sign-up accepts an age inside the valid partition

Preconditions

  • Fitness app is on the Create account screen

Steps

  1. Enter a valid email and password
  2. Enter age 35
  3. Tap Continue

Test data

age: 35 (partition 18–60)

Expected result

No error is shown and the Choose your goals screen opens.

TC-EP-02Sign-up rejects an age below the valid range

Preconditions

  • Fitness app is on the Create account screen

Steps

  1. Enter a valid email and password
  2. Enter age 12
  3. Tap Continue

Test data

age: 12 (partition 17 or less)

Expected result

The message 'You must be at least 18 to sign up' appears under the Age field, and the account is not created.

TC-EP-03Sign-up rejects an empty age field

Preconditions

  • Fitness app is on the Create account screen

Steps

  1. Enter a valid email and password
  2. Leave Age empty
  3. Tap Continue

Test data

age: (blank)

Expected result

The message 'Enter your age' appears, focus moves to the Age field, and the app does not crash.

TC-EP-04Sign-up rejects non-numeric text pasted into the age field

Preconditions

  • Fitness app is on the Create account screen
  • The text 'abc' is on the clipboard

Steps

  1. Enter a valid email and password
  2. Long-press the Age field and paste
  3. Tap Continue

Test data

age: abc

Expected result

Either the paste is blocked, or the message 'Age must be a number' appears. The account is not created.

Tip: click a test case to expand it.

Equivalence partitioning checklist

0 of 9 checked

Check your understanding

Quick quiz

0/6 answered · 0 correct

  1. 1.A cart allows 1 to 10 of an item. Which set of values is a correct minimal EP set for the number line?

  2. 2.Why should invalid partitions be tested one at a time?

  3. 3.A promo code field is optional; filled-in codes must be 6 to 10 characters. Which partition is empty input in?

  4. 4.A shop's payment screen offers Card, PayPal and Pay on delivery. How should you partition this input?

  5. 5.Shipping costs €4.99 under €20, €2.99 from €20 to €49.99, and is free from €50. You test a €35 cart and an €80 cart. What is EP's verdict?

  6. 6.The Age field opens a number keyboard on phones. Do you still need a 'not a number' partition?

Key takeaways

  • You can’t test every value, so group them: an equivalence partition is a set of values the app should treat the same way.
  • Test one representative value per partition. More values from the same partition add little.
  • Every input has valid and invalid partitions, and some partitions live off the number line: empty, not a number, wrong format.
  • Partitions exist for ranges, text lengths, option lists, formats and outputs (prices, messages, results).
  • Combine valid partitions in one test; test invalid partitions one at a time so errors can’t hide each other.
  • EP picks values from the middle of partitions. The edges need Boundary Value Analysis.

Finished this page?Nice work, this page is complete!

Mark it as done to track your progress. It's saved in this browser, no account needed.

Its review cards are now in Bites ⚡
Esc

Type to search the whole site.