Back to Blog
Lesson 7 of the Software Testing & Debugging: Testing & Debugging Foundations (QA) course
TestingJuly 25, 20264 min read

Equivalence Partitioning: Systematic Test Design for Beginners

Learn how to use equivalence partitioning to shrink your test suite without sacrificing coverage. Stop wasting time on redundant tests and start testing smarter.

testingquality assuranceunit testingsoftware engineeringbest practices
Close-up of a student filling out a multiple-choice exam in a quiet classroom setting.

Previously in this course, we explored the nuances of Happy Path vs. Edge Cases to identify what our software should—and shouldn't—do. While that helped us map out scenarios, testing every possible input is mathematically impossible. Today, we focus on equivalence partitioning, a technique that allows us to group inputs into "equivalence classes," ensuring we test efficiently without sacrificing quality.

Understanding Equivalence Partitioning from First Principles

In a perfect world, we would test every single integer, string, and object passed into our functions. In reality, our time is limited. Equivalence partitioning relies on a fundamental assumption: if a function behaves a certain way for one input in a specific range, it will behave that way for all inputs in that range.

Instead of testing every value, we divide our input domain into partitions (or classes).

  • Valid Partitions: Inputs the system is expected to accept and process correctly.
  • Invalid Partitions: Inputs the system should reject or handle as errors.

By picking just one "representative" value from each partition, we achieve the same confidence as testing every value in that set.

Identifying Partitions and Selecting Representative Values

The Texas House of Representatives chamber, featuring legislative seats and historical portraits.

Let’s advance our running project. Imagine we are building a DiscountService for an e-commerce module. Our function applyDiscount(amount: number) accepts a purchase amount and returns the discounted total.

Business Rules:

  1. Amounts between $0 and $100 get a 5% discount.
  2. Amounts between $101 and $500 get a 10% discount.
  3. Amounts above $500 are not eligible for a discount (flat rate).
  4. Negative amounts are invalid.

Mapping the Partitions

Partition TypeInput RangeRepresentative Value
Invalidamount < 0-10
Valid0 <= amount <= 10050
Valid101 <= amount <= 500250
Validamount > 500600

By selecting -10, 50, 250, and 600, we cover every logical path of the business rules. We don't need to test 51, 52, or 53 because the logic for them is identical to 50.

Worked Example: Implementing the Strategy

Here is how we translate these partitions into a simple test suite using a testing framework (like Jest or Vitest):

JAVASCRIPT
// The function to test
function applyDiscount(amount) {
  if (amount < 0) throw new Error("Invalid amount");
  if (amount <= 100) return amount * 0.95;
  if (amount <= 500) return amount * 0.90;
  return amount;
}

// The test suite applying equivalence partitioning
describe("DiscountService", () => {
  test("throws error for negative inputs", () => {
    expect(() => applyDiscount(-10)).toThrow("Invalid amount");
  });

  test("applies 5% discount for 0-100 range", () => {
    expect(applyDiscount(50)).toBe(47.5);
  });

  test("applies 10% discount for 101-500 range", () => {
    expect(applyDiscount(250)).toBe(225);
  });

  test("applies no discount for amounts above 500", () => {
    expect(applyDiscount(600)).toBe(600);
  });
});

Hands-on Exercise

Apply equivalence partitioning to a new function in your project: calculateShipping(weight: number).

  • Weights 0–5kg: $5.
  • Weights 6–20kg: $10.
  • Weights over 20kg: $20.
  • Negative weights: Throw error.

Task: Write down the partitions and identify one representative value for each. Then, write the corresponding test cases.

Common Pitfalls to Avoid

  1. Forgetting Invalid Partitions: Beginners often focus only on the "happy" ranges. Always identify what happens when the input is outside the expected bounds.
  2. Overlapping Partitions: If a value falls into two partitions, your logic is likely ambiguous. Ensure your ranges are mutually exclusive (e.g., use < 100 and >= 100).
  3. Ignoring Data Types: If your system accepts strings or objects, treat unexpected types as their own "Invalid" partition.
  4. Confusing Partitioning with Boundary Testing: Equivalence partitioning tests middle values. Testing the edges (like 0, 100, 101) is the subject of our next lesson, Boundary Value Analysis.

Frequently Asked Questions

Q: Does equivalence partitioning replace manual testing? A: No. It is a design strategy to help you write better tests. You still need to execute them.

Q: What if my partitions produce different results? A: If a range behaves differently, it’s not a single partition. Split it into two smaller, distinct partitions.

Q: Should I automate these tests? A: Yes. Once you define your representative values, they should be part of your permanent unit test suite to prevent regressions.

Recap

Equivalence partitioning turns the overwhelming task of testing "everything" into a manageable set of representative cases. By grouping inputs into valid and invalid partitions, you ensure comprehensive coverage with minimal effort. You’ve now moved from guessing which inputs to test to having a rigorous, repeatable method for test design.

Up next: Boundary Value Analysis — how to catch the bugs lurking at the very edges of your partitions.

Similar Posts