Session 3.2 - Equivalence & State Table Testing
Module 3: Dynamic & Static Testing | Duration: 1 hour
Learning Objectives
- Design efficient suites using equivalence classes and finite state tables.
- Reduce redundant test cases while preserving defect-detection power.
- Trace test cases from partitions and states to expected outcomes.
Concept Overview
Equivalence testing groups many similar inputs into partitions so one representative test can stand for each group. State table testing models system behavior across states and events to validate legal and illegal transitions.
Input/output domain coverage with minimum redundancy.
Behavior over time: current state + event + condition = next state + action.
One handles data variation; the other handles sequence and lifecycle variation.
Why Efficient Test Suites Matter
Consider a simple form with three input fields. If each field accepts values in a range of 1 to 50, testing every possible combination would require 50 × 50 × 50 = 125,000 test cases. This is clearly impractical. The challenge in software testing is to find defects with the minimum number of well-chosen test cases.
Equivalence class testing solves this by recognizing that many input values are equivalent from the software's perspective — they exercise the same logic path and should produce the same type of result. Instead of testing every value, we test one representative from each group.
A naive suite might have 30+ test cases that all exercise the same code path, wasting time without finding new defects.
The same coverage can be achieved with 5-8 tests by choosing one value from each distinct equivalence class.
Fewer tests mean faster execution, but each test must be carefully chosen to represent an entire class of behavior.
Equivalence Class Testing
Equivalence class testing (also called equivalence partitioning) divides the input domain into classes where the system is expected to behave identically for all members of a class. The key insight is: if the software handles one value in a class correctly, it will likely handle all values in that class correctly.
- Identify each input condition from the requirement (range, set of values, format, type, mandatory/optional).
- Create valid equivalence classes — groups of inputs that satisfy the requirement.
- Create invalid equivalence classes — groups of inputs that violate the requirement in a specific way.
- Pick one representative from each class. This single value stands for the entire class.
- Define expected result for each representative before execution.
- Execute and refine — if a class is too broad and hides internal boundaries, split it further.
Types of Equivalence Classes
Understanding how to identify valid and invalid classes is the most important skill in this technique.
| Input Condition Type | Valid Classes | Invalid Classes |
|---|---|---|
| Range (e.g., 1 to 100) | One class: values within [1, 100] | Two classes: values < 1, and values > 100 |
| Specific set (e.g., Red, Green, Blue) | One class for each valid value | One class: any value not in the set |
| Boolean (e.g., Yes/No) | One class: Yes | One class: No |
| Format (e.g., email address) | One class: correctly formatted inputs | Multiple classes: missing @, missing domain, special chars, etc. |
| Data type (e.g., integer expected) | One class: valid integers | Multiple classes: floats, strings, blank, special chars |
Input obeys the requirement and should be accepted or processed normally. The system should produce correct output.
Input violates exactly one rule and should be rejected with a proper error message. Each invalid class should violate a different rule.
Do not test many values from the same class — they add effort without increasing defect-detection power. One representative per class is sufficient.
Equivalence Example: Exam Score Input
Requirement: Score must be an integer from 0 to 100 inclusive.
| Class ID | Class Description | Representative | Expected |
|---|---|---|---|
| V1 | Integer in [0..100] | 56 | Accept |
| I1 | Integer < 0 | -3 | Reject |
| I2 | Integer > 100 | 101 | Reject |
| I3 | Non-integer numeric | 72.5 | Reject |
| I4 | Non-numeric text | "A+" | Reject |
| I5 | Blank input | "" | Reject |
Worked Example: Largest of Three Numbers
Requirement (from textbook): A program reads three numbers A, B, and C with range [1, 50] and prints the largest number.
- A must be an integer in [1, 50]
- B must be an integer in [1, 50]
- C must be an integer in [1, 50]
| Variable | Valid Class | Invalid Class 1 | Invalid Class 2 |
|---|---|---|---|
| A | V1: 1 ≤ A ≤ 50 | I1: A < 1 | I2: A > 50 |
| B | V2: 1 ≤ B ≤ 50 | I3: B < 1 | I4: B > 50 |
| C | V3: 1 ≤ C ≤ 50 | I5: C < 1 | I6: C > 50 |
Since the program prints the largest number, we should also partition based on which variable is largest:
| Class | Condition | Test Values (A, B, C) | Expected Output |
|---|---|---|---|
| O1 | A is largest | (45, 20, 30) | 45 |
| O2 | B is largest | (10, 48, 25) | 48 |
| O3 | C is largest | (15, 22, 40) | 40 |
| O4 | A = B = C (all equal) | (25, 25, 25) | 25 |
| O5 | A = B > C (tie for largest) | (30, 30, 10) | 30 |
State Table Based Testing
Some software behaviors depend not only on the current input but also on the history of previous inputs — that is, on the current state of the system. State table testing uses the concept of a Finite State Machine (FSM) to model and test such behavior.
(Current State, Event, Guard/Condition) → (Action, Next State)
- State: the current mode or situation of the system (e.g., Idle, Locked, Active, Blocked).
- Event: an input or trigger that occurs (e.g., Enter PIN, Click Submit, Timeout).
- Guard/Condition: an optional condition that must be true for the transition to happen (e.g., PIN is correct).
- Action: the system's response when the transition occurs (e.g., display message, update record, send alert).
- Next State: the state the system moves to after the transition.
State Graphs & Diagrams
States are represented by nodes (circles). With the help of nodes and transition links between them, a state transition diagram (or state graph) is prepared. A state graph is the pictorial representation of a Finite State Machine (FSM).
Each circle represents a distinct state of the system (e.g., Idle, Authenticated, Blocked).
Each arrow shows a possible transition, labeled with the event/condition that triggers it and the action performed.
The starting state is usually marked with an incoming arrow from nowhere. Terminal states may be double-circled.
- Identify all states and list them.
- Identify all transitions (arrows) and list event + condition for each.
- Write at least one test case that traverses each transition (transition coverage).
- Write tests for illegal transitions — events that should NOT cause a state change.
- Test sequences of transitions to cover common workflows (path coverage).
State Table Conventions
State graphs of larger systems may not be easy to understand visually. Therefore, state graphs are converted into tabular form for convenience. The following conventions are used:
| Convention | Meaning |
|---|---|
| Each row of the table | Corresponds to one state of the system |
| Each column of the table | Corresponds to one input condition or event |
| The cell at row-column intersection | Specifies the next state (transition) and the output/action, if any |
| Empty or — cell | The event is not valid in this state (illegal transition) |
Verify each defined cell: the system moves to the correct next state and performs the expected action.
Verify each empty cell: the system rejects the event and the state remains unchanged.
Validate that the system can return from error or blocked states through proper reset/unlock flows.
State Table Example: ATM PIN Attempts
Scenario: Card session starts in Idle. After 3 wrong PIN entries, account goes to Blocked.
| Current State | Event | Condition | Action | Next State |
|---|---|---|---|---|
| Idle | Insert Card | Card valid | Prompt PIN | Auth-1 |
| Auth-1 | Enter PIN | PIN correct | Show menu | Authenticated |
| Auth-1 | Enter PIN | PIN wrong | Error + retry | Auth-2 |
| Auth-2 | Enter PIN | PIN wrong | Error + retry | Auth-3 |
| Auth-3 | Enter PIN | PIN wrong | Block account | Blocked |
| Blocked | Enter PIN | Any | Deny access | Blocked |
- Happy path: Idle -> Authenticated with correct PIN first try.
- Lock path: three wrong PIN attempts lead to Blocked.
- Blocked persistence: additional attempts remain in Blocked.
- Invalid transition: transaction request before authentication should be denied.
Combining Both Techniques
For realistic systems, first choose data representatives through equivalence classes, then execute them across critical state transitions.
- Model workflow states and transitions.
- Create equivalence classes for each event input field.
- Select representative values for each class.
- Map representatives to highest-risk transitions.
- Build a compact matrix: transition x representative class.
In login flow, test valid username class, invalid format class, and locked-account class specifically on transitions LoginSubmitted and RetryAfterFailure to avoid large redundant suites.
Common Mistakes
Multiple tests from same class increase effort without new coverage.
Students often define only valid inputs and forget rejection behavior.
State testing is incomplete if only happy transitions are tested.
Verify not only next state, but also message, log, and side effects.
Class Activity
- Pick one feature with input rules and lifecycle behavior (login, booking, cart checkout).
- Create at least 5 equivalence classes (valid + invalid).
- Draw state table with at least 4 states and 6 transitions.
- Design 8-10 tests combining representatives and transitions.
- Execute or dry-run and classify defects as data-rule vs state-rule failures.
- 3 marks: Correct and complete equivalence classes.
- 3 marks: Accurate state table with valid/invalid transitions.
- 2 marks: Efficient non-redundant combined suite.
- 2 marks: Clear expected results and defect reasoning.
Exit Ticket
- For amount input 100-5000, list one valid and two invalid equivalence classes.
- Why is "wrong OTP 3 times" a state problem and not only an input problem?
- Name one test that checks an illegal transition in a library issue-return system.
Summary & Assignment
Equivalence partitioning reduces unnecessary input combinations, while state table testing ensures behavior remains correct through sequences of events. Together, they form efficient and high-impact dynamic test suites.