Worked example · Computer Science · Year 11

Testing and debugging a Python program

DCF: Producing → Evaluating and improving digital content

What this is

A complete, secure Year 11 answer, annotated so you can see which success criterion each part meets. It is also the answer key. Every result below was checked by running the program. The four faults are: line 7 uses > where it needs >=; line 13 uses or where it needs and; line 21 multiplies by 0.1 where it needs 0.9; lines 6 and 30 call int() without checking the input first, so words and empty boxes crash the program. Pupils may choose different test data; what matters is that every edge in R2, R3 and R4 is tested and the expected result comes from the requirements.

Steps 2 and 3: the test plan with results

Every age test uses 3 lessons. Every lessons test uses age 9 and the surname Jones.

No. Input tested Data Type Expected result Actual result Pass or fail
1Age9 (lessons 3)TypicalBooked: JON9, total £19.50Booked: JON9, total £19.50Pass
2Age4ExtremeAccepted: Booked: JON4, total £19.50Age must be 4 to 16Fail
3Age16ExtremeAccepted: Booked: JON16, total £19.50Booked: JON16, total £19.50Pass
4Age3ErroneousAge must be 4 to 16Age must be 4 to 16Pass
5Age17ErroneousAge must be 4 to 16Age must be 4 to 16Pass
6AgetenErroneousAge must be 4 to 16Crash, ValueError at line 6Fail
7Age(blank)ErroneousAge must be 4 to 16Crash, ValueError at line 6Fail
8Lessons1ExtremeBooked: JON9, total £6.50Booked: JON9, total £6.50Pass
9Lessons10Extreme10% off: £65.00 × 0.9 = £58.50Booked: JON9, total £6.50Fail
10Lessons5Typical, just under the discountNo discount: £32.50Booked: JON9, total £32.50Pass
11Lessons6Extreme, first discounted block10% off: £39.00 × 0.9 = £35.10Booked: JON9, total £3.90Fail
12Lessons0ErroneousLessons must be 1 to 10Booked: JON9, total £0.00Fail
13Lessons11ErroneousLessons must be 1 to 10Booked: JON9, total £7.15Fail
14LessonssixErroneousLessons must be 1 to 10Crash, ValueError at line 30Fail

Both inputs have typical, extreme and erroneous tests, and the discount is tested on both sides of the edge (5 and 6) and at the top (10). Expected results are worked out from R2 to R4, so the plan can catch the developer’s mistakes rather than copy them. Crashes are recorded with the error and the line. Evidences criteria 1 and 2.

Step 4: the faults and the fixes

Tests that failed Line(s) What is wrong, and which requirement it breaks Corrected code
27age > 4 is false when the age is exactly 4, so the youngest allowed child is rejected. Breaks R2.if age >= 4 and age <= 16:
12, 1313With or, every whole number passes: 0 is <= 10 and 11 is >= 1. Both conditions must be true. Breaks R3.if lessons >= 1 and lessons <= 10:
9, 1121Multiplying by 0.1 keeps 10% of the price instead of taking 10% off. Breaks R4.total = total * 0.9
6, 7, 146 and 30int() is called on whatever was typed, so a word or an empty box stops the program with ValueError. Breaks R2, R3 and R6.Check with .isdigit() before converting. See the corrected functions below.

The corrected validation functions and main program:

def check_age(age_text): if not age_text.isdigit(): return False age = int(age_text) if age >= 4 and age <= 16: return True else: return False def check_lessons(lessons_text): if not lessons_text.isdigit(): return False lessons = int(lessons_text) if lessons >= 1 and lessons <= 10: return True else: return False # main program, lines 29 to 33 become: if check_age(age_text): lessons_text = input("Number of lessons: ") if check_lessons(lessons_text): reference = make_reference(surname, age_text) price = block_price(int(lessons_text), int(age_text))

Rerunning all 14 tests with these changes: every test passes. Age 4 is booked as JON4 for £19.50, 10 lessons cost £58.50, 6 lessons cost £35.10, and 0, 11, “ten”, “six” and a blank box each give the correct message.

One row per fault, each with the exact line, the reason in terms of how Python evaluates it, the requirement it breaks, and a specific change. Moving the int() after an .isdigit() check fixes the crash in both places, and the full retest proves the changes worked. Evidences criteria 2 and 3.

Step 5: report and refine

(a) Siw, I ran 14 tests and 6 passed. There are four faults. Age 4 is wrongly rejected because line 7 uses > instead of >=. Any number of lessons is accepted, including 0 and 11, because line 13 uses or instead of and. Every discounted block is charged 10% of the price instead of 90%, so 6 lessons cost £3.90 instead of £35.10. Typing a word or leaving a box empty crashes the program at lines 6 and 30. The developer only tried typical values such as age 9 and 3 lessons, which all pass. Before the program goes on the desk, the four fixes must be made and all 14 tests run again.

Written for a client, not a programmer: it gives the pass rate, names each fault by its effect on the pool, explains why the developer missed them (only typical data was tried), and says what must happen next. Evidences criterion 4.

(b) The new function, with the Step 4 fix to the discount included:

def block_price(lessons, age): if age <= 7: total = lessons * 5.00 else: total = lessons * PRICE_PER_LESSON if lessons >= DISCOUNT_LESSONS: total = total * 0.9 return total

Line 33 changes to price = block_price(int(lessons_text), int(age_text)). Age 4 is already allowed by check_age, so age <= 7 covers 4 to 7.

(c)

AgeLessonsTypeExpected result
73Extreme, oldest at the lower price3 × £5.00 = Booked: JON7, total £15.00
83Extreme, youngest at the full price3 × £6.50 = Booked: JON8, total £19.50
56Typical, lower price with discount6 × £5.00 × 0.9 = Booked: JON5, total £27.00

The new function keeps the constant for the full price, fixes the discount, and puts the new rule in one place. The tests sit either side of the new edge (7 and 8) and combine the new price with the discount. Evidences criteria 3 and 5.

If you finish early: answers

Why this response is secure