Concepts / Testing and Debugging Code

Testing and Debugging Code

The computegrade function takes a score as a parameter and returns a letter grade as a string, using if and elif conditions to check thresholds from highest (A: >= 0.9) to lowest (F: < 0.6).

  • Programming

From Script to Reusable Function

A grading program becomes easier to reuse and debug when its logic is placed inside a function named computegrade. The function accepts one score and returns a letter grade as a string. Once the function works, you can call it repeatedly without rewriting the grading logic. If a result is wrong, the function gives you one focused place to investigate.

computegrade is a function that takes a score as a parameter and returns a letter grade as a string. It checks score thresholds with if and elif conditions, beginning with the highest threshold.

Score conditionReturned grade
score >= 0.9A
score >= 0.8B
score >= 0.7C
score >= 0.6D
score < 0.6F

The grading scale uses decimal scores between 0 and 1, and each listed threshold is inclusive.

Following the Threshold Cascade

The conditions must be checked from highest to lowest. For a score of 0.85, the A condition is false because 0.85 is less than 0.9. The next condition, for B, is true because 0.85 is at least 0.8, so the function returns B. It does not continue checking later conditions after finding the first true condition.

checkfalsetruescore 0.87score >= 0.9falsescore >= 0.8trueBreturned grade
Given a score such as 0.87, which condition is checked next and which branch returns the grade?
python

Tracing a Score of 0.75

Tracing computegrade(0.75)

Determine which grade is returned for a score of 0.75.

Check A: The condition score >= 0.9 is false because 0.75 is below 0.9.

Check B: The condition score >= 0.8 is false because 0.75 is below 0.8.

Check C: The condition score >= 0.7 is true because 0.75 is at least 0.7.

Stop: The function returns C immediately and does not check the D or F branches.

computegrade(0.75) returns C.

checkfalsefalsetrue0.75scoreA conditionfalseB conditionfalseC conditiontrueCreturned grade
Which conditions evaluate to false or true, and where does the function stop?

Debugging means comparing the expected path with the actual path. For 0.75, the expected result is C. If the program instead returned A or B, tracing the conditions would show that the error is in the comparison logic or in the order of the branches. Because if and elif stop at the first true condition, an incorrectly ordered cascade can prevent the correct branch from ever being reached.

Checking Boundary Values

Every threshold is inclusive. That means a score exactly equal to 0.9 receives A, exactly 0.8 receives B, exactly 0.7 receives C, and exactly 0.6 receives D. Testing only ordinary values can miss mistakes in comparison operators, so boundary values deserve their own tests.

0.89B0.79C0.69D0.59F0.90A0.80B0.70C0.60D0.91A0.81B0.71C0.61D
What grade should the function return just below, exactly at, and just above each threshold?

Handling Invalid Input

A user may enter a non-numeric value such as the word perfect instead of a score. The function should handle this situation gracefully rather than allowing the program to crash. A try-except block can attempt to convert the input to a float. If that conversion fails, the except block returns the string A Bad score.

python
Output
computegrade("perfect") returns "A Bad score"

Testing the Function Systematically

A function is not verified by testing only one convenient score. Systematic testing uses several kinds of input: values from every grade range, values exactly on the thresholds, values just below thresholds, and invalid non-numeric input. Comparing each actual result with its expected result helps reveal incorrect conditions, incorrect branch order, and missing error handling.

Test inputExpected outputPurpose
0.95ARepresentative A-range value
0.90AExact A boundary
0.85BRepresentative B-range value
0.80BExact B boundary
0.75CRepresentative C-range value
0.70CExact C boundary
0.65DRepresentative D-range value
0.60DExact D boundary
0.50FF-range value
perfectA Bad scoreNon-numeric input

A compact test set covering grade ranges, inclusive boundaries, and invalid input.

python
  • Checking thresholds from lowest to highest

    A broad low-threshold condition can become true before the function reaches the more specific higher-grade conditions.

    Fix: Check from the highest threshold downward and rely on the first true condition.

  • Forgetting that thresholds are inclusive

    The grading criteria state that a score exactly equal to a threshold receives that grade.

    Fix: Use greater-than-or-equal comparisons for the A, B, C, and D thresholds.

  • Testing only ordinary scores

    A function can appear correct for middle-of-range values while still failing at boundaries.

    Fix: Include exact thresholds and values around them in the test set.

  • Allowing non-numeric input to crash the function

    The input cannot be used as a numerical score.

    Fix: Attempt conversion inside try-except and return "A Bad score" when conversion fails.

Practice and Verification

MEDIUM

Write or inspect a computegrade function and predict the result for each input before running it: 0.99, 0.80, 0.79, 0.60, 0.59, and "unknown". Then compare every result with the grading scale and explain which condition stopped the function.

Hints
  • Start with the highest threshold for each numerical score.
  • Remember that a score exactly equal to a threshold receives that grade.
  • Treat the non-numeric input separately through the try-except path.

What do you think happens?

What does computegrade(0.80) return?

  • A
  • B
  • C
  • A Bad score
Reveal answer

Answer: B

The A condition is false because 0.80 is below 0.9. The B condition is true because 0.80 is exactly equal to the inclusive 0.8 threshold, so the function returns B.

Reliable Grade Computation

  1. computegrade turns a numerical score into a reusable letter-grade result.
  2. Conditions must be checked from the highest threshold to the lowest because the function stops at the first true condition.
  3. Thresholds are inclusive: exact values of 0.9, 0.8, 0.7, and 0.6 receive A, B, C, and D respectively.
  4. A try-except block lets the function return A Bad score for non-numeric input instead of crashing.
  5. Systematic tests should cover representative values, boundaries, values around boundaries, and invalid input.

Key Takeaways

  • A grading function is easier to reuse and debug than repeated grading statements.
  • The first true condition determines the result, so threshold order is essential.
  • Boundary tests reveal whether inclusive comparisons are implemented correctly.
  • Invalid non-numeric input should be caught and reported as A Bad score.
  • Testing across grade ranges, boundaries, and invalid inputs provides stronger evidence that the function works correctly.