Cambridge A-Level Computer Science 9618 – 12.3 Program Testing and Maintenance
12.3 Program Testing and Maintenance
Learning Objective
Analyse an existing program and make amendments to enhance functionality while ensuring reliability and maintainability.
Why Testing and Maintenance Matter
Detect and correct faults before deployment.
Ensure the program meets the specified requirements.
Reduce long‑term costs by preventing error‑propagation.
Facilitate future enhancements and adaptations.
Types of Testing
Unit Testing – test individual modules or functions in isolation.
Integration Testing – verify interactions between combined modules.
System Testing – evaluate the complete integrated system against requirements.
Acceptance Testing – confirm the system satisfies the end‑user’s needs.
Testing Techniques
Black‑box (functional) testing : focus on inputs and expected outputs without regard to internal structure.
White‑box (structural) testing : use knowledge of the code (e.g., statement coverage, branch coverage).
Boundary‑value analysis : test at the edges of input domains.
Equivalence partitioning : divide inputs into classes that should be treated similarly.
Typical Test‑Case Format
Test ID
Purpose
Input(s)
Expected Output
Result
Comments
TC01
Validate lower boundary
\$n = 0\$
“Invalid input”
Pass
TC02
Typical case
\$n = 5\$
Result = \$120\$
Fail
Off‑by‑one error in loop
Analysing an Existing Program
When presented with a piece of code, follow these steps:
Read the specification and identify functional requirements.
Trace the program manually with representative data.
Identify any violations of coding standards or design principles.
Run the existing test suite (if provided) and note failures.
Document observed faults using the test‑case format above.
Common Fault Types
Logical errors (incorrect algorithmic steps).
Off‑by‑one errors in loops or array indexing.
Incorrect use of operators (e.g., assignment “=” vs equality “==”).
Missing or inadequate input validation.
Resource leaks (e.g., files not closed).
Hard‑coded values that hinder re‑use.
Making Amendments – A Structured Approach
Identify the required enhancement – clearly state the new functionality or performance goal.
Design the change – consider impact on existing modules, data structures, and interfaces.
Update the code – apply the modification, adhering to good coding practice (meaningful names, comments, modular design).
Extend the test suite – add test cases that cover the new behaviour and regression tests for unchanged parts.
Run all tests – ensure no existing functionality is broken.
Document the change – update comments, design diagrams, and the maintenance log.
Example: Refactoring a Factorial Function
Original code (Python‑style pseudocode):
def factorial(n):
result = 1
for i in range(1, n):
result = result * i
return result
Issues identified:
Loop stops at n‑1 – off‑by‑one error.
No input validation for negative numbers.
Hard‑coded start value 1 makes the function less reusable for other products.
Amended version:
def factorial(n):
"""Return n! for non‑negative integers."""
if n < 0:
raise \cdot alueError("n must be non‑negative")
result = 1
for i in range(2, n + 1):
result *= i
return result
New test cases added (see table above) ensure the function now handles n = 0 correctly and raises an exception for negative inputs.
Documentation and Maintenance Log
Maintain a simple log entry for each amendment:
Date: 2025‑11‑22
Module: factorial.py
Change: Added input validation and corrected loop bounds.
Reason: Failed test case TC02 (off‑by‑one error) and requirement for negative‑input handling.
Tester: A. Smith
Result: All test cases now pass.
Checklist for a Successful Amendment
Requirement clearly understood and recorded.
Design impact assessed (dependencies, interfaces).
Code follows naming conventions and includes comments.
All relevant test cases (old and new) executed.
Documentation updated (code comments, design diagrams, maintenance log).
Peer review performed where possible.
Suggested Diagram
Suggested diagram: Flowchart showing the testing cycle – Write test → Run test → Record result → Fix fault → Re‑run test → Pass.
Summary
Effective testing and maintenance involve systematic analysis, rigorous test design, careful code amendment, and thorough documentation. By following the structured approach outlined above, students can reliably enhance existing programs while preserving – and often improving – overall software quality.