Condition Testing is a stronger version of [Decision/Branch Testing](/codex/decision-branch-testing). While branch coverage is focused on branches alone, condition testing is focused on all the boolean subexpressions of the branching conditions.
### Multiple condition testing
Multiple condition testing is analogous to [Decision Table Testing](/codex/decision-table-testing) and relies on testing all possible combinations of condition sub-expressions.
### Condition determination testing
A more efficient technique involves figuring out which conditions independently affect a decision outcome and only testing those. This technique analogous to collapsing of decision trees in [Decision Table Testing](/codex/decision-table-testing).
### Worked example
Consider the OpenZeppelin `findUpperBound` function below in the `Arrays` library:
-- CODE language-solidity --
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* `array` is expected to be sorted in ascending order, and to contain no
* repeated elements.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
if (array.length == 0) {
return 0;
}
uint256 low = 0;
uint256 high = array.length;
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds down (it does integer division with truncation).
if (array[mid] > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && array[low - 1] == element) {
return low - 1;
} else {
return low;
}
}
If we focus on the last `if` statement, there are only two branches:
- `low` > `0` && `array[low - 1] == element`
- `low` <= `0 || array[low - 1] != element` (the inverse condition).
However, there are four possible condition combinations:
- `low` > `0` && `array[low - 1] == element`
- `low` <= `0` && `array[low - 1] == element`
- `low` > `0` && `array[low - 1] != element`
- `low` <= `0` && `array[low - 1] != element`
These are developed by considering the two subexpressions (`low` > `0` and `array[low - 1] == element`) and how they independently affect the branch condition outcome.