Learning Objectives
By the end of this lesson you will be able to:
- Explain operator precedence and its effect on boolean expressions
- Identify the two most common precedence-related specification mismatches
- Design test cases that distinguish between
A || (B && C)and(A || B) && C
What Is Operator Precedence?
In mathematics, multiplication has higher precedence than addition: 2 + 3 × 4 = 2 + 12 = 14, not 5 × 4 = 20.
In most programming languages, && (AND) has higher precedence than || (OR). This means:
A || B && C
is actually parsed as:
A || (B && C)
Not (A || B) && C. These are different logical expressions. If a developer writes the first intending the second, the behavior differs — and the bug only manifests in specific input combinations.
The Two Interpretations
Specification: "Free shipping applies if the user is a VIP member, OR if the order total exceeds €150 AND it includes 3 or more items."
Interpretation 1 (what the developer intended): isVIP || (total > 150 && itemCount >= 3) → VIPs always get free shipping; non-VIPs need both conditions
Interpretation 2 (what a misread could produce): (isVIP || total > 150) && itemCount >= 3 → Even VIPs need 3+ items
These give the same result in many cases. They differ exactly when:
- isVIP=true, total=50, itemCount=1 → Interpretation 1: free shipping. Interpretation 2: paid shipping.
The Test Cases That Catch Precedence Bugs
For any A || B && C expression, test:
- A=true, B=false, C=false → Both interpretations agree: true (A wins)
- A=false, B=true, C=true → Both agree: true (B&&C wins)
- A=true, B=true, C=false → Interpretation 1: true (A wins). Interpretation 2: false (C fails)
- A=false, B=true, C=false → Interpretation 1: false. Interpretation 2: false. Both agree.
The critical test: A=true and C=false. If the developer wrote (A || B) && C, a VIP member without enough items gets charged for shipping.
The Parenthesis Problem
The root cause is rarely malice or carelessness — it's the invisible parentheses that programming languages add silently. A developer writing a complex condition doesn't always see them.
The tester's advantage: you don't need to read the code. You need to design inputs that distinguish between the two readings of the specification, then observe which behavior the system actually produces.
Pro Tip: Whenever you see a compound condition mixing
&&and||without explicit parentheses in the spec, write two interpretations and design one test case that distinguishes them. That case is worth more than five happy-path tests.
Short-Circuit Evaluation: A Related Trap
In most languages, A || B stops evaluating as soon as A is true. This means if A is always true in your tests, you never exercise B at all. Make sure at least some test cases have A=false to force evaluation of B.
Similarly for A && B: test with A=false to verify B is never evaluated (and that the system handles A=false gracefully without relying on B being non-null).
Summary
Operator precedence bugs are specification-level ambiguities realized as code. The developer read the requirement one way; the language parsed their code another. Your job is to design the test that distinguishes between the two interpretations — and to do it without reading a single line of source code.