Testing Your Solutions Checkpoint
A review of this module. Skip it if you feel confident; the next module does not need it.
Fix the mistakes
The slips that cost marks in this module. Spot each one, then check the fix.
This checkpoint brings the module together: trace to find the bug, choose edge cases, write quick asserts and stress test a fast solution against a brute force. The examples use orders, marks and totals.
Trace before you change
A test table is a list of inputs with the expected answers, run in one loop so that each new case costs one line.
A function should count orders at or above a limit, but it is one short. Trace it on a tiny list first, so you fix the cause and not a guess.
def count_at_least(amounts, limit): count = 0 for a in amounts: if a > limit: count += 1 return count
print(count_at_least([100, 50, 200], 100))The trace shows a > limit is False for 100, but the statement says at or above. Change > to >=.
Pick cases, then assert them
List the borders from the statement: empty, one item, the exact limit, negatives. Put them in a table and assert each answer.
def count_at_least(amounts, limit): return sum(1 for a in amounts if a >= limit)
cases = [ (([], 10), 0), (([10], 10), 1), (([9, 10, 11], 10), 2), (([-5, -1], -3), 1),]for args, want in cases: got = count_at_least(*args) assert got == want, f"{args}: got {got}, expected {want}"print("passed", len(cases))Example 1 · A fixed boundary check
def count_at_least(amounts, limit): return sum(1 for a in amounts if a >= limit)
print(count_at_least([100, 50, 200], 100))print(count_at_least([], 100))2 0
What this code does
- The exact limit, 100, now counts, so the first line shows 2.
- The empty list gives 0 with no special case.
Example 2 · Properties of a merge
def merge(a, b): return sorted(a + b)
for a, b in (([], []), ([1], []), ([1, 4], [2, 3]), ([2, 2], [2])): out = merge(a, b) assert len(out) == len(a) + len(b) assert out == sorted(out) print(a, b, out)[] [] [] [1] [] [1] [1, 4] [2, 3] [1, 2, 3, 4] [2, 2] [2] [2, 2, 2]
What this code does
- Two properties hold for every case: the length adds up and the result is in order.
- The cases include empty, equal values and interleaved values.
The table covers the empty list, the exact limit and a negative limit. The message names the failing case.
Stress test the fast version
For a faster solution, keep the simple version as a reference. Draw small seeded inputs and compare. The first mismatch is your test case.
Example 3 · A stress test finds the start-value bug
import random
def slow(nums): return max(sum(nums[i:j]) for i in range(len(nums)) for j in range(i + 1, len(nums) + 1))
def fast(nums): best = cur = 0 for x in nums: cur = max(x, cur + x) best = max(best, cur) return best
rng = random.Random(3)for _ in range(1000): nums = [rng.randint(-3, 3) for _ in range(rng.randint(1, 4))] if slow(nums) != fast(nums): print(nums, slow(nums), fast(nums)) break[-2] -2 0
What this code does
- The fast version starts at 0, so it answers 0 when every item is negative.
- The printed list is the test case to trace.
Example 4 · Stress test the fast version
import random
def slow(nums): return max(sum(nums[i:j]) for i in range(len(nums)) for j in range(i + 1, len(nums) + 1))
def fast(nums): best = cur = nums[0] for x in nums[1:]: cur = max(x, cur + x) best = max(best, cur) return best
rng = random.Random(1)for _ in range(500): nums = [rng.randint(-3, 3) for _ in range(rng.randint(1, 6))] assert slow(nums) == fast(nums), numsprint("no difference")no difference
What this code does
- No difference on 500 inputs is good evidence, not proof.
- Running it prints
no difference.
Module quiz
Questions from the whole module. Your first answer is your score.
Problems
Graded easy to hard, using everything from this module.
Try each one yourself first. Use the hint if you get stuck. Mark it as done when it works.
Exercise 1· Easy
A loop should total all marks, but it starts at index 1. For marks = [40, 25, 35] print the total with the loop fixed.
100
Exercise 2· Easy
Print max of the empty list [] as 0, without an error, using a default.
0
Exercise 3· Medium
Test count_at_least(amounts, limit) that counts values at or above the limit. Assert ([9, 10, 11], 10) -> 2 and ([], 10) -> 0, then print ok.
ok
Exercise 4· Medium
Print the second largest distinct value of [8, 8, 5, 9, 9] as 8.
8
Exercise 5· Medium
Catch a failing assert. Run assert [1, 2] == [2, 1], "order matters" and print only the message.
order matters
Exercise 6· Hard
Stress test sum(range(n + 1)) against n * (n + 1) // 2 for n from 0 to 499 and print 500 agree.
500 agree
Exercise 7· Hard
Find the first failing round. A buggy fast_max starts at 0. With random.Random(2) and lists of length 1 to 3 with values -4 to -1, print the number of the first round (counting from 1) where it differs from max.
1
Exercise 8· Hard
Compare two ways to count how many values in a list are below the average. Use random.Random(7), 300 lists of length 1 to 6 with values 0 to 9, a loop version and a sum version, and print 300 agree.
300 agree
Interview questions
Questions interviewers ask on this topic.
Finish up
Mark complete & continue
Next: Must-do problems: Testing Your Solutions