Selecting test data
Selecting and Justifying Test Data
Knowing the three categories of test data is only the first step. The harder skill is looking at a specific algorithm and deciding exactly which values to test - then being able to explain why each value was chosen. This is what examiners mean by "select and justify": the selection is the list of test values, and the justification is the reasoning that explains what each value is designed to reveal.
A complete justification answers three questions for each test value:
- What category does it belong to? (normal, boundary, or erroneous)
- Why was this specific value chosen? (e.g. it is the exact lower boundary, or it is just above the upper limit)
- What would a wrong answer tell you? (i.e. what error would it expose if the output is incorrect)
The tabs below show three different algorithms. For each one, read the pseudocode, then study the test data table - focusing on the "Justification" column, which models the reasoning expected in an exam answer.
Three Algorithms - Three Test Plans
Year Group Checker (valid range: 7 to 13 inclusive)
INPUT year
IF year >= 7 AND year <= 13 THEN
OUTPUT "Valid year group"
ELSE
OUTPUT "Invalid year group"
ENDIF
How to derive the test data: the algorithm has two comparison conditions (>=7 and <=13). Each produces two boundary values: 6 and 7 for the lower limit; 13 and 14 for the upper. Normal data should be clearly inside the range. Erroneous data tests wrong type.
| Value | Category | Expected output | Justification |
|---|---|---|---|
| 10 | Normal | Valid year group | Middle of the valid range - confirms basic logic works for a typical input. |
| 6 | Boundary | Invalid year group | Just below the lower limit. If the algorithm incorrectly uses > instead of >=, this value would not catch it - but it confirms the area just below is correctly rejected. |
| 7 | Boundary | Valid year group | Exactly at the lower limit. If >= is incorrectly written as >, this value returns "Invalid" - directly exposing the comparison error. |
| 13 | Boundary | Valid year group | Exactly at the upper limit. Tests whether 13 is correctly included. |
| 14 | Boundary | Invalid year group | Just above the upper limit. Confirms the first value above the range is rejected. |
| "ten" | Erroneous | Error / rejected | Wrong data type. Tests whether the program handles a non-integer input without crashing. |
PIN Validator (valid: exactly 4 digits, all numeric)
INPUT pin
IF LEN(pin) == 4 AND pin IS_NUMERIC THEN
OUTPUT "Valid PIN"
ELSE
OUTPUT "Invalid PIN"
ENDIF
How to derive the test data: there are two independent conditions - length (exactly 4) and type (all digits). Each condition needs to be tested when met and when not met. Boundary testing for length means 3, 4, and 5 characters. The type check needs both a fully numeric and a mixed-character test.
| Value | Category | Expected output | Justification |
|---|---|---|---|
| "5823" | Normal | Valid PIN | 4 digits, all numeric - a typical correct PIN. Confirms the core logic accepts valid input. |
| "123" | Boundary | Invalid PIN | One character too short. Confirms length = 3 is correctly rejected. |
| "12345" | Boundary | Invalid PIN | One character too long. Confirms length = 5 is correctly rejected. |
| "58a3" | Erroneous | Invalid PIN | Correct length but contains a letter. Tests the IS_NUMERIC condition independently of the length check. |
| "" | Erroneous | Invalid PIN | Empty string. Tests behaviour when no input is given - a common real-world edge case. |
Score Grader (boundaries: A=90+, B=75+, C=60+, D=40+, F=below 40)
INPUT score
IF score >= 90 THEN
OUTPUT "A"
ELSEIF score >= 75 THEN
OUTPUT "B"
ELSEIF score >= 60 THEN
OUTPUT "C"
ELSEIF score >= 40 THEN
OUTPUT "D"
ELSE
OUTPUT "F"
ENDIF
How to derive the test data: with multiple grade boundaries, each threshold (40, 60, 75, 90) needs testing both at and just below. The range 0 to 100 also needs testing at its extremes (0 and 100). Scores below 0 or above 100 are erroneous.
| Value | Category | Expected output | Justification |
|---|---|---|---|
| 50 | Normal | D | Clearly in the D range - tests the algorithm works for a straightforward case. |
| 90 | Boundary | A | Exactly at the A threshold. Tests whether >= 90 correctly includes 90. |
| 89 | Boundary | B | Just below the A threshold. If the condition were > rather than >=, this would be fine - but 90 would give the wrong grade. |
| 75 | Boundary | B | Exactly at the B threshold. Tests the boundary between B and C. |
| 40 | Boundary | D | Exactly at the D/F boundary - the most critical threshold, as failing to include 40 would wrongly classify a passing score as F. |
| 0 | Boundary | F | Minimum possible score. Tests the algorithm at the bottom of the valid range. |
| 100 | Boundary | A | Maximum possible score. Tests the algorithm at the top of the valid range. |
| -1 | Erroneous | Error / rejected | Below 0 - an impossible score. Tests robustness against invalid input. |
| 101 | Erroneous | Error / rejected | Above 100 - an impossible score. Tests robustness at the upper extreme. |
Key Takeaways
- Selecting test data means identifying which specific values to test. Justifying test data means explaining why each value was chosen and what error it would expose if the output is wrong.
- The starting point is always the algorithm's conditions: every comparison operator and every stated limit generates a set of boundary values that must be tested.
- Each grade boundary, age limit, or length threshold needs at least two boundary tests: the value exactly at the limit (which should be accepted) and the value just outside it (which should be rejected or produce a different result).
- When an algorithm has multiple independent conditions (e.g. length AND type), each condition should be tested in isolation as well as in combination - this ensures both checks are working independently.
- Erroneous data must be justified too: "tests what happens when an impossible or wrong-type value is entered" is a complete justification for this category.