TT Lab
Get started
Learn Learning paths Courses

Testing Tools in Practice

Design principles: Catch real faults with boundary tests

Continue in TT Lab

Summary

A good boundary-value test tells a plausibly wrong implementation apart from the correct one.

Why this matters

Even a ten-line price calculator charges the wrong amount on every order if a single boundary is wrong. A test that checks that price(3) is 1050 still passes even if the >= at the discount threshold is changed to >. Instead of repeating many middle values, you should choose the point just before, exactly at, and just after the point where the condition changes. This lab does not read the numbers in a coverage report. You run the tests you wrote against the correct code, and then run them again against code with one wrong condition, and actually observe the difference.

How it works

Input Contract
Integer 0 0
Integers 1–9 350 per item
Integers 10–100 300 per item for the whole quantity
Integer out of range ValueError
Non-integer value or bool TypeError

The discount is not a progressive scheme that applies only after the 10th item; it changes the unit price of the whole quantity. If you write tests without this sentence, you end up arguing about which implementation is right under different policies. The test names and expected amounts should make the meaning of the policy visible.

What it looks like in the field

In Python, bool is a subclass of int, so isinstance(True, int) is true. The language does not decide whether a business can accept the quantity True as 1 item. This contract rejects it explicitly, so bool is treated as a separate counterexample. On the other hand, if you check the variable names or the number of if statements in the implementation, you mistake a refactoring with the same behavior for a bug. You must observe inputs, results, and exceptions.

What you will do in the next lab

You accumulate eight tests: 0, 1, just before the discount, at the boundary, just after, the maximum, a negative number, and a wrong type. If a test fails against the correct implementation, fix the expected value of the test first. Even if it fails against a defective implementation, a syntax error or an import error does not count as detecting the defect. The assertion of an executed test must fail, or an exception unexpected in the test must occur while it runs. Catching every one of these defect samples is evidence for the contract you verified, not proof that there are no bugs at all.

See also: Getting started with pytest