- Understand the three types of programming error — syntax, execution, and logic — and how they differ
- Select appropriate normal, extreme, and exceptional test data for a given program
- Design a complete test plan that documents test cases with expected results
- I can identify whether a given error is a syntax, execution, or logic error and justify my answer
- I can explain what each error type does — whether the program fails to run, crashes at runtime, or gives wrong output
- I can give an example of each error type in Python code
- I can select appropriate normal, extreme, and exceptional test data for a program, stating expected results
- I can design a complete test plan using a table with test number, description, test data, expected result, and type
Answer before the lesson begins. These check prior knowledge — it's fine if you're unsure.
1. A pupil types primt("Hello") in Python. The program does not run at all and Python immediately shows an error. What type of error is this?
2. A program accepts pupil ages from 11 to 18 (inclusive). Which of the following is the best example of extreme test data?
3. A program runs without crashing, but every total it calculates is slightly too high. What type of error is this?
Key vocabulary
Testing: Errors and Test Plans
Why testing matters
Testing is a fundamental stage in the software development process. Once a program has been written, it must be tested systematically to verify that it works correctly for all expected inputs — and that it handles unexpected inputs gracefully. A program that works for one input but fails for another is not finished. The SQA N5 specification requires you to understand the types of errors that can occur and how to design a structured test plan to catch them.
Type 1 — Syntax errors
A syntax error occurs when the code breaks the grammar rules of Python. Python reads through your code before running it, and if it finds a syntax error it stops immediately and displays an error message. The program never runs at all.
Common causes of syntax errors include:
- A missing colon after
if,elif,else,for,while, ordef - Wrong or missing indentation
- An unclosed bracket, parenthesis, or quotation mark
- A misspelled keyword (e.g.
primtinstead ofprint) - Using
=where==is needed inside a condition
Syntax errors are the easiest to fix — Python points directly to the line where the problem was detected. Once fixed, the program will at least start running.
if age >= 16 # SyntaxError: expected ':' at end of if statement
print("Old enough")
Type 2 — Execution errors (run-time errors)
An execution error (also called a run-time error) occurs after the program has started running. The syntax is correct, so Python has no complaints before the program begins — but something goes wrong during execution and the program crashes with an error message.
Common causes of execution errors include:
- Dividing by zero (
ZeroDivisionError) - Accessing a list index that does not exist (
IndexError) - Trying to convert an incompatible value, such as
int("hello")(ValueError) - Using a variable before it has been assigned a value (
NameError)
Execution errors are often caused by unexpected user input. For example, a program that expects a number will crash if the user types a word instead.
scores = [10, 20, 30]
print(scores[5]) # IndexError: list index out of range
# (valid indices are 0, 1, 2 — there is no index 5)
Type 3 — Logic errors
A logic error occurs when the program runs from start to finish without crashing, but the output is wrong. Python gives no error message because the code is syntactically valid and executes without incident — the problem is in the programmer's reasoning, not in the code structure.
Logic errors are the hardest to find because there is no error message to guide you. You must trace through the code manually, checking each step, to spot where the logic breaks down.
Common causes of logic errors include:
- Using
>when you meant>=(or vice versa) — causes off-by-one issues at boundaries - Using the wrong operator:
+instead of*, or-instead of/ - Initialising a variable to the wrong value (e.g. starting a minimum-finder at 0 instead of
array[0]) - A loop running one iteration too many or too few
total = 0
for i in range(1, 6):
total = total * i # Logic error: should be total + i
print(total) # Outputs 0 (not 15) — no error message, just a wrong answer
The trace: total=0. i=1: 0*1=0. i=2: 0*2=0. i=3: 0*3=0. …. Because 0 multiplied by anything is always 0, total never changes. The correct line is total = total + i.
Summary — the three error types at a glance
| Error type | When detected | Program runs? | Error message? | Typical cause |
|---|---|---|---|---|
| Syntax | Before running | Never starts | Yes — points to the line | Missing colon, typo in keyword, unclosed bracket |
| Execution | During running | Starts, then crashes | Yes — states the error type | Divide by zero, invalid index, wrong data type conversion |
| Logic | When checking output | Runs fully | No — output is wrong silently | Wrong operator, bad initialisation, off-by-one in loop |
Types of test data
When testing a program, you must choose test data that covers all scenarios. The SQA specification requires three types:
Normal test data — typical, realistic values well within the valid input range. The program should accept these and produce the correct output. Example: for a program that accepts scores from 0 to 100, normal data might be 45, 67, or 80.
Extreme (boundary) test data — values at the exact edges of the valid range: the minimum and maximum acceptable values. The program should accept these. Extreme data is critical because off-by-one logic errors (using > instead of >=) only reveal themselves at the boundary. Example: for 0 to 100, extreme data is exactly 0 and exactly 100.
Exceptional test data — values outside the valid range, or the wrong data type altogether. A well-written program should reject these and display an appropriate error message. Example: for 0 to 100, exceptional data might be -1, 101, or the text "hello".
Designing a test plan
A test plan is a structured table listing every test case. Writing the test plan before running the program forces you to think about what the correct behaviour should be — the expected result must be written down before testing, not inferred from the output. This is what makes testing rigorous rather than guesswork.
A complete test plan includes for each test case:
- Test number — a reference identifier
- Description — what the test is checking
- Test data — the specific value(s) used
- Expected result — what the program should do with this input
- Type — normal, extreme, or exceptional
For a program that accepts a score between 0 and 100, a test plan might look like this:
| Test | Description | Test data | Expected result | Type |
|---|---|---|---|---|
| 1 | Typical valid score | 50 | Score accepted, result displayed | Normal |
| 2 | Typical valid score | 75 | Score accepted, result displayed | Normal |
| 3 | Minimum valid score | 0 | Score accepted, result displayed | Extreme |
| 4 | Maximum valid score | 100 | Score accepted, result displayed | Extreme |
| 5 | One below minimum | -1 | Error message: "Invalid score" | Exceptional |
| 6 | One above maximum | 101 | Error message: "Invalid score" | Exceptional |
| 7 | Wrong data type | "hello" | Error message: "Invalid score" | Exceptional |
Notice that exceptional test data includes values just outside the range (−1, 101) as well as completely wrong data types ("hello"). The values just outside the boundary are particularly important — they test whether the validation uses >= versus > correctly.
Worked examples
Three code snippets are shown below. Identify the type of error in each and explain what happens when the code runs.
name = input("Enter your name: ")
if len(name) > 0
print("Hello,", name)
Syntax error. The if statement is missing its colon at the end. Python detects this before running and raises a SyntaxError. The program never starts.age = int(input("Enter your age: "))
print(100 / (18 - age)) # if age is 18, this divides by zero
Execution error. The syntax is valid, so the program starts. But if the user enters 18, the calculation becomes 100 / 0, which raises a ZeroDivisionError and crashes the program mid-execution.total = 0
for i in range(5):
total = total * i # should be total + i
print("Sum 0–4:", total) # outputs 0, not 10
Logic error. The program runs and prints a result, but the result is wrong. total * i starts at 0×0=0 and stays 0 throughout, because any number multiplied by 0 is 0. The intended operation was total + i, which would give 0+0+1+2+3+4=10.A program accepts passwords between 8 and 20 characters (inclusive) and rejects anything else. Identify appropriate normal, extreme, and exceptional test data.
Expected result for both: "Password accepted".
>= and <= (inclusive) rather than > and < (exclusive).Expected result for both: "Password accepted".
Expected result for all: "Password too short" or "Password too long" — rejected.
A program asks the user to enter their age. If the age is between 11 and 18 (inclusive), it displays "Secondary pupil". Otherwise it displays "Not secondary age". Design a complete test plan.
| Test | Description | Test data | Expected result | Type |
|---|---|---|---|---|
| 1 | Typical age in range | 14 | "Secondary pupil" | Normal |
| 2 | Typical age in range | 16 | "Secondary pupil" | Normal |
| 3 | Minimum valid age | 11 | "Secondary pupil" | Extreme |
| 4 | Maximum valid age | 18 | "Secondary pupil" | Extreme |
| 5 | One below minimum | 10 | "Not secondary age" | Exceptional |
| 6 | One above maximum | 19 | "Not secondary age" | Exceptional |
| 7 | Negative number | -5 | "Not secondary age" | Exceptional |
| 8 | Wrong data type | "fifteen" | Error / rejected | Exceptional |
if age > 11 instead of if age >= 11, then entering 11 (test 3) would wrongly give "Not secondary age". The extreme test catches this off-by-one logic error — normal data (14, 16) would not.The code below is supposed to count how many values in the list are between 50 and 100 (inclusive), but it gives the wrong answer. Identify the logic error and fix it.
scores = [45, 72, 38, 88, 50, 61, 100]
count = 0
for i in range(len(scores)):
if scores[i] > 50 and scores[i] < 100: # logic error
count = count + 1
print("Count:", count)> 50 and < 100). This excludes the boundary values 50 and 100 themselves. Tracing with the array: 45? No. 72? Yes (count=1). 38? No. 88? Yes (count=2). 50? No — 50 is not >50. 61? Yes (count=3). 100? No — 100 is not <100. Output: Count: 3. But the correct answer is 5 (72, 88, 50, 61, 100 all fall in the range 50 to 100 inclusive).> to >= and < to <= to make the boundary inclusive:
if scores[i] >= 50 and scores[i] <= 100: # correctedTrace with fix: 45? No. 72? Yes (count=1). 38? No. 88? Yes (count=2). 50? Yes (count=3). 61? Yes (count=4). 100? Yes (count=5). Output:
Count: 5. Verified ✓A program asks the user to enter a score out of 10. If the score is 7 or above, it displays "Pass". If the score is between 1 and 6 (inclusive), it displays "Fail". If the score is outside 1 to 10, it displays "Invalid score".
Answer the following:
- Identify one normal, two extreme, and two exceptional test values for this program. For each, state the expected result.
- The programmer wrote
if score > 7instead ofif score >= 7. What type of error is this? What wrong output would entering 7 produce? - Design a test plan with at least six rows covering all three types of test data.
-
Normal: 8 → "Pass" (typical value, well within the pass range).
Extreme: 1 → "Fail" (minimum valid score); 10 → "Pass" (maximum valid score).
Exceptional: 0 → "Invalid score" (one below minimum); 11 → "Invalid score" (one above maximum). -
Logic error. The program runs without crashing, but when the user enters 7, the condition
score > 7evaluates to False (since 7 is not strictly greater than 7). The program falls through to the next condition and outputs "Fail" instead of the correct "Pass". There is no error message from Python — it is a silent wrong answer. -
Test Description Test data Expected result Type 1 Typical pass score 8 "Pass" Normal 2 Typical fail score 4 "Fail" Normal 3 Minimum valid score 1 "Fail" Extreme 4 Maximum valid score 10 "Pass" Extreme 5 Pass/fail boundary 7 "Pass" Extreme 6 One below minimum 0 "Invalid score" Exceptional 7 One above maximum 11 "Invalid score" Exceptional 8 Wrong data type "ten" "Invalid score" or crash if no validation Exceptional
Error type questions are a staple of the N5 SDD paper. The three command words used are "identify", "describe", and "explain". "Identify" just needs the name (syntax / execution / logic). "Describe" needs the name plus what happens (e.g. "a syntax error means the program will not run"). "Explain" needs the name, what happens, and why — including a reference to the code shown in the question.
For test data questions, always give specific values — not just descriptions. "A number within the range" is not acceptable; "the value 50" (for a 0–100 program) is. The expected result must also be specific: "the program displays 'Score accepted'" rather than just "it works". Vague answers lose marks even if the idea is correct.
The pass/fail boundary is always worth a test case. In a question about test plans, do not just include two extreme values (minimum and maximum of the valid range) — also test the exact value where the output changes. For a "score ≥ 7 is a pass" program, this means testing 7 (should pass) and 6 (should fail). These boundary tests are worth dedicated rows in your test plan.
Questions 1–5 are auto-checked. Questions 6–10 are self-marked — write your answer, then reveal the model answer to check your work.
1. Which type of error causes a program to crash during execution after it has already started running? TYPE 1
2. A program accepts temperatures from −20°C to 50°C. Which value is extreme (boundary) test data? TYPE 1
3. Which of the following is an example of a syntax error? TYPE 1
4. A program accepts PINs that are exactly 4 digits (1000 to 9999). A tester enters the value "abcd". What type of test data is this? TYPE 1
5. The following Python code runs without any error message, but the output is wrong. What type of error does it contain?
price = 12.50
discount = 0.10
final = price + discount # should subtract, not add
print("Final price: £", final)
TYPE 1
6. The code below is meant to check whether a number entered by the user is positive (greater than zero). Identify the type of error, describe what happens when the user enters 0, and write the corrected code.
number = int(input("Enter a number: "))
if number > 0:
print("Positive")
elif number = 0: # error here
print("Zero")
else:
print("Negative")
TYPE 2
Error type: Syntax error. The line elif number = 0: uses a single equals sign (=) for assignment inside a condition. Python requires == (double equals) for comparison. Python raises a SyntaxError before the program runs at all.
What happens when the user enters 0: Nothing — the program never runs. Python flags the syntax error immediately and refuses to execute any code.
Corrected code:
number = int(input("Enter a number: "))
if number > 0:
print("Positive")
elif number == 0: # corrected: == for comparison
print("Zero")
else:
print("Negative")
7. Explain the difference between an execution error and a logic error. For each, give one specific example in Python and state what the programmer must do to fix it. TYPE 2
Execution error: Occurs while the program is running — the syntax was correct so the program started, but something goes wrong during execution and the program crashes with an error message.
Example: names = ["Ali", "Sam"]; print(names[5]) — this raises an IndexError because index 5 does not exist in a 2-element list. Python displays the error and stops.
Fix: Check array bounds before accessing, or use a try/except block to catch the error.
Logic error: The program runs fully from start to finish without crashing, but the output is incorrect. Python gives no error message — the code is valid, just wrong in its reasoning.
Example: average = total / 5 when there are actually 6 values — the program runs fine but the average is wrong.
Fix: Trace through the code step by step with known test data to locate where the calculation goes wrong, then correct the logic.
8. A program asks a pupil to enter the number of hours they revised, which must be between 0 and 8 (inclusive). Identify appropriate normal, extreme, and exceptional test data for this program. For each value, state the expected result. TYPE 2
Normal test data (typical, valid values within the range):
3 → accepted, displays result. 5 → accepted, displays result.
Extreme (boundary) test data (at the exact edges of the valid range):
0 → accepted (the minimum valid input). 8 → accepted (the maximum valid input).
Exceptional test data (outside the valid range or wrong type):
−1 → rejected, error message "Invalid hours". 9 → rejected, error message "Invalid hours". "two" → rejected (wrong data type — cannot convert to an integer).
Note: the values −1 and 9 are just outside the boundaries (one below minimum, one above maximum) — these are the most important exceptional values because they test the validation condition directly.
9. The program below is supposed to count how many scores in the list are 50 or above, but the output is wrong. Identify the type of error, trace through the code to show the incorrect output, and write the corrected code with a trace to verify the fix.
scores = [45, 55, 70, 38, 50, 82]
count = 0
for i in range(len(scores)):
if scores[i] > 50: # error: should be >= 50
count = count + 1
print("Count:", count)
TYPE 3
Error type: Logic error — the program runs without crashing, but gives the wrong count because the boundary value 50 is excluded by > instead of >=.
Trace of buggy code: i=0: 45>50? No. i=1: 55>50? Yes (count=1). i=2: 70>50? Yes (count=2). i=3: 38>50? No. i=4: 50>50? No — 50 is not strictly greater than 50, so it is excluded. i=5: 82>50? Yes (count=3). Output: Count: 3. But the correct answer is 4 (55, 70, 50, 82 are all ≥ 50).
Corrected code:
scores = [45, 55, 70, 38, 50, 82]
count = 0
for i in range(len(scores)):
if scores[i] >= 50: # corrected: >= includes the boundary value
count = count + 1
print("Count:", count)
Trace of corrected code: i=0: 45≥50? No. i=1: 55≥50? Yes (count=1). i=2: 70≥50? Yes (count=2). i=3: 38≥50? No. i=4: 50≥50? Yes (count=3). i=5: 82≥50? Yes (count=4). Output: Count: 4. Verified: 55, 70, 50, 82 are all ≥ 50 ✓
10. Design a complete test plan for the following program. Include at least 7 test cases covering all three types of test data. For each test, give the test number, a description, the test data, the expected result, and the type (normal, extreme, or exceptional).
The program: asks the user to enter a number of items to order (valid range: 1 to 99). If valid, it displays "Order placed". If invalid, it displays "Please enter a number between 1 and 99".
TYPE 3
| Test | Description | Test data | Expected result | Type |
|---|---|---|---|---|
| 1 | Typical quantity in range | 10 | "Order placed" | Normal |
| 2 | Typical quantity in range | 50 | "Order placed" | Normal |
| 3 | Minimum valid quantity | 1 | "Order placed" | Extreme |
| 4 | Maximum valid quantity | 99 | "Order placed" | Extreme |
| 5 | One below minimum | 0 | "Please enter a number between 1 and 99" | Exceptional |
| 6 | One above maximum | 100 | "Please enter a number between 1 and 99" | Exceptional |
| 7 | Negative number | −5 | "Please enter a number between 1 and 99" | Exceptional |
| 8 | Wrong data type | "ten" | "Please enter a number between 1 and 99" (or execution error if no type check) | Exceptional |
Key points: Tests 3 and 4 are the most important extreme tests — they check that 1 and 99 are included in the valid range (not accidentally excluded by > or <). Tests 5 and 6 (values just outside the boundary) are crucial for catching off-by-one logic errors. Test 8 (wrong data type) checks whether the program handles non-integer input gracefully.
Suggested timing: 60 minutes. Warm up 8 min; notes 15 min (use the summary table on the board); worked examples 12 min; now you try 8 min; task set 17 min.
Key misconception to address: Pupils almost always confuse extreme and exceptional. Reinforce with the mnemonic: Extreme = Edge (still valid, still accepted); Exceptional = Excluded (outside the range, must be rejected). Ask pupils to predict: for a range of 1–10, is the value 10 extreme or exceptional? (Extreme — it is the maximum valid value.) What about 11? (Exceptional — just outside the range.)
Live demo suggestion: Run the logic error from Example 4 live. Show the code, ask pupils to predict the output before running. When the wrong answer appears, ask them to trace through it to find the error before revealing the fix. This models the debugging process explicitly and shows why test plans with expected results are essential — you only notice the error because you knew the correct answer in advance.
Assignment link: Test plans appear in the N5 assignment (SDD task 1). Pupils who have practised writing structured test plan tables here will find the assignment section much less daunting. Emphasise that the expected result column must be filled in before running tests — markers check this.
Extension question: Ask pupils to write Python code for a simple number validator (e.g., accepts 1–10), then swap programs with a partner. Each pupil executes the test plan on their partner's program and reports whether the actual results match the expected results. This turns Q10 from a paper exercise into a practical debugging task.
SQA command words covered: "identify" (Q1, Q3, Q4, Q5, Q6, Q9), "describe" (Q7), "explain" (Q7), "design" (Q8, Q10). The exam frequently pairs "identify the type of error" with "describe what happens" — ensure pupils practise answering both parts.