Lesson 4 of 9 · Last manual lesson

Test Techniques: Static & Dynamic

Static Testing · EP & BVA (numeric & non-numeric) · Decision Tables · State Transition

→ next slide  |  ESC overview

Lesson Plan
Lesson 4: Test Techniques — Static & Dynamic

1. Two families of testing

2. Static techniques — find bugs without running

3. Dynamic black-box — EP, BVA

4. Decision Tables

5. State Transition Testing

Homework
Photo order testing: Decision table and coverage analysis

Two Families of Testing

Static Testing Examine the work product without executing it.

Reviews, walkthroughs, inspections, static analysis tools.

Finds issues in: requirements, design docs, code, test cases.
Dynamic Testing Run the software and observe its behaviour against expected outcomes.

Black-box, white-box, grey-box techniques.

Finds issues in: running applications at any test level.
Key Insight

Static testing finds bugs before code runs — often 10× cheaper to fix.
Both families complement each other; neither replaces the other.

Static Techniques — Code & Document Reviews

Walkthrough Author leads the team through the document/code step by step.
Goal: share knowledge + collect feedback.
Inspection Most formal.
Defined roles: moderator, author, reviewers, scribe. Defects logged, metrics collected.
Informal Review A colleague quickly reads your work and gives verbal feedback. No process, no documentation. Fast and low cost.
Technical Review / Pull Request Review Author opens a PR, reviewers leave inline comments on specific lines.
Tracked in Git — every comment, change, and approval is recorded.
This is the daily reality of code review in software teams.

Peer Review in Practice — PR Comment Style

Reviewing this function as a pull request — what would you flag?

// Rental Car — calculates total price
function calcPrice(days, ratePerDay) {
  var total = days * ratePerDay
  if (days > 7)
    total = total - total * 0.1   // 10% discount
  return total
}
Issues to raise
  • var — use const/let
  • No input validation (negative days?)
  • Discount threshold — is 7 confirmed with requirements?
Good things to mention too Logic is simple and readable.
Discount formula is correct.
Constructive PR reviews mention both. Tone matters — comments are read by a person, not a compiler.

Static Analysis Tools

Tools that analyse source code automatically — no human reviewer needed.

Linters ESLint (JS), Pylint (Python) — enforce code style and catch obvious errors before tests even run.
Type Checkers TypeScript, mypy — catch type mismatches at compile time, not at runtime in production.
Security Scanners Snyk, SonarQube, Dependabot — find known vulnerabilities in your code and dependencies.
In the real world

Most CI/CD pipelines run a linter and a security scanner on every pull request. Your code never ships if the static checks fail.

Dynamic Testing: Black-box vs White-box

Black-box Tester does not know the internal implementation.

Tests are derived from requirements and specifications.
Applicable at any test level. Used by most functional/QA testers.
White-box Tester knows the internal implementation.

Tests are designed to achieve code coverage — lines, branches, paths.

Typically used by developers for unit/integration testing.

Grey-box = some knowledge of internals. Common in API testing and security testing.

Equivalence Partitioning (EP)

"Divide inputs into groups where every value in the group should behave the same way. Test one value per group."

EP reduces the number of test cases without reducing coverage.
If one value in a partition fails, they all likely fail.
If one passes, they all should pass.

Three kinds of partitions

Valid partition — inputs the system should accept and process normally
Invalid partition — inputs the system should reject
Boundary — the exact edges (covered by BVA, next slide)

EP Example 1 — Youth Bus Ticket

Requirement: youth discount applies to passengers aged 6–17. Age must be a whole number.

< 6 Invalid (too young)
Test: age = 3
Expect: no discount, or age validation error
6 – 17 Valid (youth)
Test: age = 12
Expect: youth ticket price applied
> 17 Invalid (adult)
Test: age = 25
Expect: full adult price
Negative Invalid input
Test: age = −5
Expect: validation error
Non-integer Invalid input
Test: age = 12.5
Expect: validation error

EP Example 2 — File Upload Type

Requirement: only .pdf, .jpg, .png files may be uploaded. All other types must be rejected.

Allowed types .pdf · .jpg · .png
Test: upload photo.jpg
Expect: file accepted
Rejected types .exe · .php · .zip · .js
Test: upload script.exe
Expect: "File type not allowed"
No file Empty selection
Test: submit with no file chosen
Expect: "Please select a file"
EP works for any input type

Partitions can be categories, file types, roles, formats — any set of inputs that should behave identically. One test value per partition is enough.

EP Example 3 — Password Length

Requirement: password must be 8–20 characters. Spaces not allowed.

1–7 chars Too short
Test: "abc123" (6 chars)
Expect: "Password too short"
8–20 chars Valid
Test: "Secret#99" (9 chars)
Expect: password accepted
> 20 chars Too long
Test: "abcdefghij1234567890X"
Expect: "Password too long"
Empty string Test: ""
Expect: validation error
Contains space Test: "pass word1"
Expect: "Spaces not allowed"

Boundary Value Analysis (BVA)

"Bugs love boundaries. Test the exact edge values — on, just below, and just above."

EP tells you which partition to test.
BVA tells you which specific values to use.
Bugs are most common where one partition meets another — developers often use < vs ≤ incorrectly.

2-value BVA (ISTQB standard)

For each boundary: test the last value inside the partition and the first value outside.
For the range 6–17: test 5 & 6 (lower boundary) and 17 & 18 (upper boundary).

BVA Example 1 — Youth Bus Ticket (6–17)

Rule: ages 6–17 get youth ticket. Full price otherwise.

Lower boundary (6):

5 ✗
BOUNDARY
6 ✓

Upper boundary (17):

17 ✓
BOUNDARY
18 ✗
What goes wrong? A developer writes age > 6 instead of age >= 6. Age 6 gets adult price. Only a boundary test catches this.
Total tests from EP + BVA: 3 (one per partition) + 4 boundary values = 7 well-chosen tests that give high confidence.

BVA Example 2 — Booking Date

Requirement: bookings can only be made for today or a future date. Past dates must be rejected.

Boundary: today's date (lower bound of the valid range)

Yesterday ✗
BOUNDARY
Today ✓

Also test inside the valid range:

Tomorrow ✓
·
+6 months ✓
·
1 Jan 2000 ✗
BVA on non-numeric types

Dates, strings, and ordered categories all have boundaries. Yesterday vs today is just as much a boundary as 17 vs 18.
Think: "what value sits right at the edge of valid/invalid?"

BVA Example 3 — Long-rental Discount

Requirement: rentals over 7 days get a 10% discount. Exactly 7 days pays full price.

7 days — full price ✓
BOUNDARY
8 days — 10% off ✓
// Buggy implementation — which boundary value catches this?
if (days >= 7)            
  total = total * 0.9;
Test value 7 reveals the bug Renting exactly 7 days applies the 10% discount incorrectly.
The test expected full price but got a discount.
Without boundary testing, this off-by-one error ships to production.

Decision Tables

"When multiple conditions combine to produce different outcomes — use a table."

Decision tables are perfect for business rules.
Each column is one combination of conditions.
You test every combination (or a prioritised subset).

Structure Rows: conditions (inputs) + actions (outputs)
Columns: test cases (rule combinations)
Cells: T/F for conditions, expected result for actions
When to use Login rules · Pricing with multiple discounts · Eligibility checks · Any rule with 2+ interacting conditions

Decision Table Example 1 — Login

Rule: user logs in with email + password. Account may be locked. All three conditions affect the outcome.

Condition / Action TC 1TC 2TC 3TC 4TC 5
Valid email?
Correct password?
Account locked?
Outcome Email error Wrong pwd Login OK Locked msg Locked msg

5 test cases cover all meaningful combinations. Each column becomes one test case in your test suite.

Decision Table Example 2 — Rental Pricing

Rules: loyalty member gets 5% off · Over 7 days gets 10% off · Both discounts can stack.

Condition / Action TC 1TC 2TC 3TC 4
Loyalty member?
Over 7 days?
Discount applied None (full price) 5% off 10% off 14.5% off
Watch out

TC 4: stacked discounts. Is 14.5% correct (5% then 10% on remainder) or 15% (5+10%)?
The table forces you to ask the business. Ambiguity found before coding saves days of rework.

Decision Table Example 3 — Photo Print Order

Rules: orders over €50 get free shipping · New customers get a welcome coupon · Both can combine.

Condition / Action TC 1TC 2TC 3TC 4
Order > €50?
New customer?
Free shipping? NoYesNoYes
Welcome coupon? NoNoYesYes

With 2 conditions each having 2 values → 2² = 4 combinations. Always check: are all combinations realistic?

State Transition Testing

"Systems move through states. Test that every transition happens correctly — and that invalid transitions are blocked."

Use when the system's behaviour depends on its current state plus an event or input.
Common in: login flows, order lifecycles, booking systems, device firmware.

Key concepts State — a condition the system is in
Event — a trigger that causes a transition
Action — what happens during the transition
Guard — condition that must be true for transition
Test coverage goals All states visited at least once
All valid transitions exercised
All invalid transitions attempted (should be rejected)

State Transition Example 1 — Login Lockout

Rule: 3 failed logins locks the account. Correct login resets the counter.

Idle
→ fail →
1 Fail
→ fail →
2 Fails
→ fail →
Locked
Idle ←
— correct login —
1 Fail / 2 Fails
Tests for invalid transitions
  • Try to login while Locked — should stay Locked
  • Try to reset via URL while Locked — should be rejected
  • 4th correct login after lockout — should still be Locked
Tests for valid transitions
  • Idle → fail → 1 Fail (counter shows correctly)
  • 2 Fails → correct login → Idle (counter resets)
  • 2 Fails → fail → Locked (lock triggers exactly on 3rd)

State Transition Example 2 — Car Rental Lifecycle

A rental booking moves through defined states from creation to completion.

Draft
→ confirm →
Confirmed
→ pick-up →
Active
→ return →
Completed
Cancelled
← cancel (from Draft or Confirmed)
From stateEventExpected resultInvalid?
CompletedcancelError — cannot cancel✗ Invalid
ActiveconfirmError — already active✗ Invalid
Confirmedpick-upMoves to Active✓ Valid

State Transition Example 3 — E-commerce Order

Order states in a typical online shop — each with allowed and blocked transitions.

Placed
Processing
Shipped
Delivered
Refunded
← from Delivered only
Cancelled
← from Placed or Processing
What to test

Can you refund a Placed order? (Should be blocked)
Can you ship a Cancelled order? (Blocked)
Does Placed → Processing → Cancelled prevent shipment?
These are the tricky edges that bugs hide in.

When to Use Each Technique

TechniqueBest forOutput
Peer Review Any work product before testing Issue list
EP Inputs with clear valid/invalid ranges Representative test values
BVA Numeric ranges, off-by-one errors Edge-case test values
Decision Table Multi-condition business rules One test case per column
State Transition Systems with distinct states & flows Valid + invalid transition tests

Real testers combine techniques — EP+BVA together, Decision Tables for business rules, State Transition for workflow validation.

From Techniques to Automated Tests

The connection you've been building toward

Manual techniques →

  • EP partitions → test data sets in unit tests
  • BVA edge values → parameterised tests
  • Decision table columns → test cases in describe/it blocks
  • State transitions → integration test flows
  • State transitions → E2E Playwright flows

Automation gives you

  • Run 200 EP/BVA tests in 2 seconds
  • Every git push triggers the full test suite
  • Regression: every bug fix gets a test that never forgets
  • Confidence to refactor safely

Homework — Decision Table & Coverage Analysis

Discount logic for a vacation photo print website:

const customer = { isRegistered: false, isBirthday: false }
const order    = { photoCount: 3, hasFrames: false }

console.log(calculateDiscount(customer, order))

function calculateDiscount(customer, order) {
  let discount = 0;
  if (customer.isRegistered) {
    if (customer.isBirthday) {
      discount = 8;
    } else {
      discount = 5;
    }
  }
  if (order.photoCount > 10) { discount += 3; }
  if (order.hasFrames)       { discount += 3; }
  return discount;
}

🔗 onecompiler.com/javascript/44h474k2m

Two test cases are already written:

TC-1: Guest user orders 3 photos, no frames → 0% discount
TC-2: Registered user orders 3 photos, no frames, not their birthday → 5% discount
  1. Decision Table — Write down all combinations of the 4 conditions and the resulting discount %
  2. Statement Coverage — How many statements do TC-1 and TC-2 cover? Which are missed?
  3. Branch Coverage — How many branches do TC-1 and TC-2 cover? Which are missed?
  4. Fix the gaps — Write the minimum test cases needed for 100% statement coverage
💡 Draw a diagram of the if-branches if it helps visualise the workflow!
End of Lesson 4 · Manual testing complete

Manual testing: done.

You now have the full toolkit: requirements analysis, test documentation, bug reporting, and all major test design techniques.

Lesson 5 starts the automation track — same techniques, automated execution.

← L3 Bug Reports  |  L5 Unit Testing & Automation →