This is the first post on a series of test case heuristics. Test case heuristics patterns used to help decide the next test to write and ensure test coverage of requirements.
The boundary test heuristic applies to requirements which specify different behavior on either side of a particular value (called a boundary value) within a range of values.
For example, a requirement specifies that more inventory should be ordered if the number of units in the warehouse drops below 50. In this case, 50 is a boundary value.
A requirement often has several boundary values (see example below). The range of values on either side of a boundary value (or in between two boundary values) is called a partition.
The boundary test heuristic says that at least one test case should exist for each boundary value and each partition. It is useful to pick values very close to the boundary value to ensure that the code specifies the proper condition.
Boundary testing helps:
- Clarify and identify gaps in the requirements
- Provide coverage for conditional statements
- Prevent mistakes arising from using the wrong comparison operator (e.g. coding “<”, when “<=” was intended).
The business sets the following discount structure to encourage higher sales:
- If the order total is between $50 and $100 then a 5% discount is applied.
- If the order total is more than $100 and less than $200 then a 10% discount is applied.
- If the order total is more than $200 than a 15% discount is applied.
This requirement specifies three boundaries: $50, $100, and $200. There are four partitions.
<--------------|-----------------|---------------|--------------> par 1 50 par 2 100 part 3 200 par 4
As we choose certain test cases, we are forced to ask certain clarifying questions, such as:
- $49.99: What should happen when the order total is less than $50. The requirement didn’t say.
- $50.00: When the requirement says “between”, did the they mean to include or exclude $50 and $100.00. The word “between” can mean different things in regards to including the end points.
- $200.00: The requirement doesn’t say what happens if the order total is $200.
Notice that the number of decimal places is important. The value $49.99 was chosen above because we’re dealing with a monetary value. However, in another context, a different number of decimal places may be relevant.
Null: While null is not truly a boundary value, it is a special value in most languages (particularly SQL).
Relative boundaries: Many times a boundary is specified in terms of another input. For example, return (2 * x) if x > y. In this case, y is a boundary value.
Dates and times: Boundary testing for dates and times must take into account the precision of the value (e.g. Is it a date only? Are hours and minutes relevant? How about seconds or milliseconds?). Dates and times are often used with relative boundaries. For example, a citizen is allowed to vote if they are at least 18 years old; the boundary (18 years) is relative to the citizen’s date of birth.
Boundaries on multiple inputs: Sometimes a requirement will specify boundary values on a variety of inputs. For example, a patient should be admitted if their respiratory rate is >= 30 and their age is >= 65. Combining boundary testing and all-pairs testing can be extremely valuable in coming up with appropriate tests when there are many inputs.
Output boundaries: Sometimes boundaries will be specified as part of a required output. This is often the case for a non-deterministic process. For example, a player will receive a random prize between $50 and $100.