29-testing-errors-test-data.py
python-programming / robust-programming  ·  Lesson 30
Lesson 30 — Robust programming

Testing, Errors & Test Data

Find defects systematically and choose test data that checks the full valid range.

Testing should happen during development and again when the completed program is ready. Test data should include normal, boundary, invalid and erroneous cases.

Predict

Read the code first. Do not run it yet.

testing-errors-test-data-predict.py
age = 16
if age > 16:
    print("Allowed")
else:
    print("Not allowed")
Predict before running
  • What is printed?
  • If the intended rule is “16 or over”, is there a logic error?
  • Which operator should be changed?

Investigate

Use this code to explain exactly how the program works.

testing-errors-test-data-investigate.py
minimum = 1
maximum = 100
value = 100
valid = value >= minimum and value <= maximum
print(valid)
Investigate the code
  • Is 100 normal or boundary test data for the valid range 1 to 100?
  • What other boundary value should be tested?
  • Give one invalid value of the correct type and one erroneous value of the wrong type.

Syntax and logic errors

Error typeMeaningExample
Syntax errorBreaks the grammatical rules of the language and prevents correct translation/executionmissing colon after an if statement
Logic errorThe program runs but produces an unexpected resultusing > when >= was required

Test-data categories

TypeMeaningExample for valid age 11–16
Normalvalid data comfortably inside the allowed range14
Boundaryvalid data at the edge of the allowed range11 or 16
Invalidcorrect data type but should be rejected10 or 17
Erroneousincorrect data type and should be rejected"twelve"

Testing during and after development

Iterative testing checks modules and changes while the program is being developed. Final/terminal testing checks the completed program at the end of development.

InputTypeExpected resultActual resultPass?
14NormalAcceptedAcceptedYes
11BoundaryAcceptedAcceptedYes
10InvalidRejectedRejectedYes
"twelve"ErroneousRejected—To test
Refine after testingWhen testing exposes a problem, correct the algorithm or code and test again. Testing and refinement are an iterative process.
Purpose of testingTesting checks whether a program behaves as intended, helps reveal defects, and provides evidence for refining the algorithm or code before it is considered complete.

Self-study guide

Testing checks whether a program behaves as intended and helps programmers find defects before the program is trusted. OCR requires the purpose of testing, iterative and final/terminal testing, syntax and logic errors, normal/boundary/invalid/erroneous test data, refining algorithms, and the ability to create or complete a test plan.

Testing is strongest when data is chosen deliberately. Randomly trying a few values is much weaker than selecting values because each one challenges a specific rule or boundary.

OCR focusKnow the exact OCR definitions of syntax error, logic error and the four test-data categories. Be able to design a test plan containing expected and actual results, and distinguish iterative from final/terminal testing.

OCR Exam Reference Language ↔ Python

OCR Exam Reference Language / termPythonWhat to remember
Syntax errore.g. missing Python colonBreaks grammatical rules and stops the program being run/translated normally.
Logic errore.g. `>` instead of `>=`Program runs but produces unexpected/incorrect output.
Iterative testingtesting modules during developmentUsed while developing and refining.
Final / terminal testingtesting completed program at endChecks the complete product.
Normal datavalid ordinary valueShould be accepted without causing errors.
Boundary datavalid value at edgeCorrect type and on the very edge of validity.
Invalid datacorrect type, should be rejectedOutside the accepted rule.
Erroneous dataincorrect data type, should be rejectedWrong type for the expected input.
Read both formsIn an examination you may see OCR Exam Reference Language even when you have learned the idea in Python. Translate the structure, not just the symbols.

Worked example

A test plan makes the expected result explicit before the program is executed.

lesson-30-worked.py
def valid_score(value):
    if type(value) != int:
        return False

    if value < 0 or value > 100:
        return False

    return True

test_data = [50, 0, 100, -1, 101, "fifty"]
expected = [True, True, True, False, False, False]

for index in range(len(test_data)):
    actual = valid_score(test_data[index])
    passed = actual == expected[index]
    print(test_data[index], expected[index], actual, passed)
Output
50 True True True
0 True True True
100 True True True
-1 False False True
101 False False True
fifty False False True
Work through it line by line
  • 50 is normal valid data.
  • 0 and 100 are valid boundary values.
  • -1 and 101 are invalid because they have the correct numeric type but are outside the valid range.
  • "fifty" is erroneous because the program expects an integer but receives a string.
  • The expected result is decided before execution; the actual result is recorded after execution.
  • passed shows whether actual behaviour matches the expectation.

Another example

Boundary data is especially effective at exposing comparison mistakes.

lesson-30-example-2.py
total = 30

if total > 30:
    print("Free delivery")
else:
    print("Delivery charge")
Output
Delivery charge
Why this example matters
  • If the rule says 30 or more should receive free delivery, the program contains a logic error.
  • The boundary value 30 exposes the error immediately.
  • The condition should be total >= 30.

Common mistakes

Avoid these errors
  • Calling a logic error a syntax error just because the answer is wrong.
  • Calling invalid numeric data “erroneous”; OCR defines erroneous data as the wrong data type.
  • Using only normal data and forgetting boundaries.
  • Writing test data without an expected result, making it harder to decide objectively whether the test passed.
  • Confusing iterative testing during development with final/terminal testing after production.
Exam-safe warningOCR definitions matter: invalid = correct type but should be rejected; erroneous = incorrect data type and should be rejected.

Exam-ready checklist

You should now be able to
  • Define syntax and logic errors precisely.
  • Distinguish iterative from final/terminal testing.
  • Choose normal, boundary, invalid and erroneous data for a scenario.
  • Create/complete a test plan with expected and actual results.
  • Use failed tests to refine an algorithm or program.

What you have learned

  • Syntax errors break language rules; logic errors produce unexpected results.
  • Use normal, boundary, invalid and erroneous test data.
  • Iterative testing happens during development; final/terminal testing happens at the end.
  • A test plan records inputs, expected results, actual results and whether each test passed.