Module 5 Session 5.6 Prioritization Types & Techniques

Prioritization Types & Techniques

Compare general, version-specific, and model-based approaches with sample algorithms — Chowdhury Chapter 10 | ISTQB Foundation Level §5.1

Learning Objectives
  • Distinguish the three prioritization types: general, version-specific, and model-based.
  • Apply the total and additional greedy coverage algorithms for general prioritization.
  • Apply change-impact and modification-traversing algorithms for version-specific prioritization.
  • Describe ML/ANN model-based prioritization and its advantages over heuristic methods.
  • Select the appropriate prioritization type for a given development context.
  • Combine general and version-specific prioritization in a single ordered suite.

Prioritization Types vs. Techniques

Session 5.5 established the goals of prioritization. This session covers the types (the scope of information used) and the specific algorithms (techniques) within each type.

TypeInformation UsedStabilityBest For
General Prioritization Properties of test cases independent of any specific version: coverage, historical FER, execution cost Stable across versions — recalculate infrequently Nightly regression; stable products; when change data is unavailable
Version-Specific Prioritization Change information for the current version P′: which code changed, impact analysis results Changes every version — recalculate per release CI/CD gates; targeted regression after a specific change; hotfix releases
Model-Based Prioritization Trained ML/statistical model using historical suite + defect + coverage data Improves over time with more data Large mature suites (>1,000 cases); products with rich execution history

Type 1: General Prioritization

General Prioritization

Definition: An ordering of all test cases in the suite based on properties that are independent of any specific software version or change set. The priority order is reusable across multiple regression cycles (with periodic recalculation).

Input data:

  • Coverage profile of each case (which statements/branches it exercises).
  • Historical fault exposure rate (FER) over the last N runs.
  • Execution time of each case.
  • Risk and business value ratings (from a stable risk register, not version-specific).

General Prioritization Algorithms

Algorithm 1: Total Coverage Greedy

Principle: Rank each case by its total statement/branch coverage count. Cases covering more code run first.

Step 1: For each test case ti, compute |cov(ti)| = total number of unique branches/statements covered.
Step 2: Sort test cases in descending order of |cov(ti)|.
Step 3: Execute in this order. Cases with the same coverage count: break ties by FER (higher FER first).

Advantage: Simple; no iteration needed. Disadvantage: Two cases covering the same 50 branches are equally ranked even though together they cover only 50 branches, not 100. The additional algorithm corrects this.

Algorithm 2: Additional Coverage Greedy (Recommended)

Principle: At each step, select the case that covers the most additional (not yet covered by previously selected cases) branches/statements. This is the greedy set-cover ordering.

Step 1: Initialise: ordered_list = []; covered = ∅.
Step 2: Select tk = argmaxt ∉ ordered_list |cov(t) \ covered|. Add tk to ordered_list. Update covered = covered ∪ cov(tk).
Step 3: Repeat until all cases are ordered (or covered = all branches).
Step 4: If multiple cases tie on new coverage, break tie using FER (higher first), then execution time (shorter first).

Advantage: Maximises coverage rate — the fastest accumulation of coverage as tests execute. Research (Rothermel et al.) shows additional coverage greedy produces APFD values 10–20% higher than total coverage greedy.

Algorithm 3: FER-Based Greedy

Principle: Sort cases by descending historical fault exposure rate. The case most likely to find a defect (based on history) runs first.

Best for: Mature stable products where the code doesn't change much but defect patterns are well-established. Less effective for products under active development where change information should dominate.

Type 2: Version-Specific Prioritization

Version-Specific Prioritization

Definition: An ordering that uses information about the specific change from version P to P′ to rank test cases. Cases that exercise changed code are elevated. This ordering changes with every version and must be recalculated per release.

Input data (version-specific):

  • Diff between P and P′: which functions/lines were modified, added, or deleted.
  • Impact analysis: which modules depend on the changed module.
  • Control/data flow: which test cases exercise the changed paths.
Key insight: A test case that exercises changed code is more likely to detect a regression than a test case that exercises unchanged, stable code. Version-specific prioritization exploits this by elevating changed-code cases regardless of their general coverage or historical FER.

Version-Specific Prioritization Algorithms

Algorithm 4: Change-Impact Prioritization

Principle: Assign each test case a change-impact score based on how much of the changed code it exercises.

Step 1: From the diff (P → P′), build Δ: the set of changed statements/functions.
Step 2: For each ti, compute CI(ti) = |cov(ti) ∩ Δ| / |Δ|. This is the fraction of changed code exercised by ti.
Step 3: Sort by descending CI(ti). Ties broken by FER then execution speed.

Cases with CI = 0 (exercise no changed code) are deprioritized to the end of the queue — but still run. This differs from selection (where CI=0 cases would be excluded).

Algorithm 5: Modification-Traversing (Firewall) Prioritization

Principle: Identify the "firewall" — all modules modified or directly dependent on a modified module. Test cases that traverse the firewall (exercise at least one firewall entity) are elevated to P1.

Step 1: Identify directly modified modules (DM) from the change set.
Step 2: Perform impact analysis: identify all modules that call or import from DM. Together, DM + dependent modules form the firewall F.
Step 3: Test cases that exercise any entity in F are assigned P1. Remaining cases are ordered by general prioritization (additional coverage greedy).

Advantage: Simpler than CI(ti) calculation; can be performed with module-level impact analysis tools without needing statement-level coverage data for the changed code.

Version-specific algorithm comparison:
AlgorithmGranularityTool RequirementAccuracy
Change-Impact (CI score)Statement/branch levelStatement coverage tool + diffHighest: precise fraction of changed code exercised
Modification-Traversing (Firewall)Module levelModule dependency graph + diffMedium: binary (firewall or not) — misses intra-module change proximity

Type 3: Model-Based Prioritization

Model-Based / ML-Based Prioritization

Concept: Train a predictive model on historical execution data (inputs: test case features, code metrics, coverage; output: probability of failure) and use the model's failure probability prediction as the priority score.

Features used as model inputs:

  • Code churn (lines changed per module over recent history)
  • Historical failure count for the test case
  • Cyclomatic complexity of the changed function
  • Test case age (newer tests tend to have higher FER initially)
  • Coverage overlap with recently failing cases
  • Time since last execution

Model architectures used in research: Logistic regression, random forest, gradient boosting (XGBoost), LSTM (for sequential execution history). LSTM approaches (Spieker et al., 2017) have shown APFD improvements of 15–30% over greedy heuristics on large CI datasets.

Model-based prioritization workflow:
Offline training phase: Collect historical execution data (N past runs). Train model on features + failure outcomes. Validate APFD on held-out test runs.
Online scoring phase (per CI run): Extract current features (code churn, coverage, execution history). Run model inference. Sort test cases by descending predicted failure probability.
Retraining trigger: Retrain model after every 50–100 runs or when APFD on recent runs drops below baseline. Model drift is the main operational risk.
When model-based prioritization is justified:
  • Suite size > 1,000 cases (heuristics degrade; model learns patterns heuristics miss).
  • Rich execution history available (≥ 200 historical runs with defect labels).
  • Team has ML engineering capacity to build, deploy, and maintain the model.
  • APFD gain over greedy > 10% (validate this before committing to model maintenance overhead).

Type Comparison

DimensionGeneralVersion-SpecificModel-Based
Recalculation frequencyPer sprint or releasePer commit / change setPer run (inference) + periodic retraining
Data requiredCoverage + FER historyDiff + impact analysisRich historical execution log
Implementation complexityLow (sort by score)Medium (requires diff integration)High (ML pipeline)
APFD vs. randomModerate improvementHigh improvement for targeted changesHighest improvement at scale
Robustness to cold startGood (works with minimal history)Good (works with any change diff)Poor (needs significant history)
Best suited forStable products; nightly regressionActive development; CI gates; hotfixesLarge mature CI systems

Combining Types in Practice

Real-world CI/CD pipelines typically combine version-specific and general prioritization in a two-tier approach:

Tier 1 (Version-Specific): P1 band — Run all test cases with CI(ti) > 0 (exercises changed code) or firewall tests first. These are most likely to reveal regressions from the current change. Run in descending CI score order.
Tier 2 (General): P2–P4 bands — Run remaining test cases (CI = 0; do not exercise changed code) in additional-coverage-greedy order with FER tiebreaking. These are stability regression checks.
Practical combined algorithm:
1. Compute CI(ti) for all ti using the current diff.
2. Partition: Tchanged = {t : CI(t) > 0}; Tunchanged = {t : CI(t) = 0}.
3. Order Tchanged by descending CI score (version-specific tier). These run first.
4. Order Tunchanged by additional coverage greedy with FER tiebreaking (general tier). These run after.
5. Final ordered suite = [Tchanged ordered] + [Tunchanged ordered].

Worked Example: Applying Both Types

Scenario: An inventory management system. 8 test cases. Current change: Bug fix in the calculate_reorder_point() function (Module: Stock).

Coverage and FER data:
TCFeatureBranchesChanged Branches (Δ)CI ScoreFER
TC-I01Reorder point (standard)B1, B2, B3, B7B2, B32/4 = 0.500.6
TC-I02Reorder point (seasonal)B1, B3, B4, B7B3, B42/4 = 0.500.4
TC-I03Reorder point (zero lead time)B2, B3, B5B2, B32/3 = 0.670.7
TC-I04Stock receiptB6, B8, B9(none)0.000.5
TC-I05Stock issueB8, B10, B11(none)0.000.3
TC-I06Low-stock alertB7, B12, B13B7 (indirect)1/3 = 0.330.8
TC-I07Supplier orderB9, B14, B15(none)0.000.2
TC-I08Audit trailB16, B17(none)0.000.1

Changed branches Δ = {B2, B3, B4, B7} (4 total). Note: B7 is touched only indirectly by the fix.

Step 1: Version-specific tier (Tchanged ordered by CI descending, FER tiebreak):
  1. P1 TC-I03 (CI=0.67, FER=0.7)
  2. P1 TC-I01 (CI=0.50, FER=0.6) — tie on CI, higher FER wins
  3. P1 TC-I02 (CI=0.50, FER=0.4)
  4. P2 TC-I06 (CI=0.33, FER=0.8)
Step 2: General tier — additional coverage greedy on Tunchanged {TC-I04, TC-I05, TC-I07, TC-I08}:

Branches already covered by Tchanged: {B1, B2, B3, B4, B5, B7, B12, B13}.

IterationSelectedNew BranchesReasoning
1TC-I04B6, B8, B9 (3 new)Most new branches; B8,B9 not yet covered
2TC-I05B10, B11 (2 new)B8 already covered; 2 new branches
3TC-I07B14, B15 (2 new)B9 already covered; 2 new branches
4TC-I08B16, B17 (2 new)Last remaining
Final combined execution order:
  1. P1 TC-I03 — Reorder point (zero lead time)
  2. P1 TC-I01 — Reorder point (standard)
  3. P1 TC-I02 — Reorder point (seasonal)
  4. P2 TC-I06 — Low-stock alert
  5. P3 TC-I04 — Stock receipt
  6. P3 TC-I05 — Stock issue
  7. P4 TC-I07 — Supplier order
  8. P4 TC-I08 — Audit trail

All cases that exercise the changed code run in the first 4 positions. If a 30-minute time box only completes TC-I03 to TC-I05, all changed-code coverage is verified and a significant portion of the unchanged code is also checked.

Common Mistakes

Using general prioritization for hotfixes
General prioritization does not know what changed. A hotfix that modifies the payment module may have high-priority payment tests ranked P3 by general FER if they haven't recently failed. Always use version-specific prioritization for targeted changes.
Using version-specific prioritization as the only gate
If CI only runs version-specific P1 cases, the stability regression (unchanged code) is never checked. A change in module A may cause a latent defect in module C to manifest. General prioritization for the unchanged suite is still needed.
Recalculating general priority every commit
General priority is stable across versions. Recalculating it on every commit wastes resources. Recalculate general priority on a schedule (weekly, or after each minimization event). Recalculate version-specific priority on every change.
Applying model-based prioritization without sufficient history
An ML model trained on 20 execution runs will overfit and perform worse than a simple greedy heuristic. Model-based approaches require at minimum 100–200 historical runs with defect labels to show consistent improvement over heuristics.

Class Activity

Scenario: An e-commerce platform has 10 test cases. The current change modifies the apply_coupon() function. Changed statements: S3, S5, S7, S9 (4 statements).
TCFeatureStatements CoveredFER
TC-E01Apply 10% couponS1, S3, S5, S70.7
TC-E02Apply expired couponS2, S3, S60.5
TC-E03Apply coupon at thresholdS3, S5, S8, S90.6
TC-E04Apply invalid coupon codeS2, S4, S60.4
TC-E05Apply 50% couponS1, S5, S7, S90.8
TC-E06Cart subtotal calculationS10, S11, S120.3
TC-E07Payment processingS13, S14, S150.9
TC-E08Order confirmation emailS16, S170.2
TC-E09Apply coupon + loyalty pointsS3, S7, S9, S180.5
TC-E10Coupon + free shipping comboS5, S9, S19, S200.4
Tasks:
  1. Compute the Change-Impact score CI(ti) for each test case. (|Δ| = 4 changed statements: S3, S5, S7, S9.)
  2. Partition into Tchanged (CI > 0) and Tunchanged (CI = 0).
  3. Order Tchanged by descending CI score. Break ties with FER.
  4. Apply the additional coverage greedy algorithm to Tunchanged. Show all iterations.
  5. Produce the final combined execution order. If a 20-minute time box fits 6 cases (assume 3-4 min each), which cases are completed? What risk areas are covered?

Exit Ticket

  1. What is the key difference between general and version-specific prioritization? Give one example of when each should be the dominant approach.
  2. A test case has CI(t) = 0 after a change. Should it be excluded from the regression run? Justify your answer in terms of the difference between prioritization and selection.
  3. Describe the "additional coverage greedy" algorithm in 3 steps. Why does it produce higher APFD values than the "total coverage greedy" algorithm?
  4. Under what conditions would you recommend model-based prioritization over the combined general+version-specific heuristic approach?

Summary & Assignment

Three prioritization types address different information contexts. General prioritization uses stable properties (coverage, FER, execution time) and is recalculated periodically. Version-specific prioritization uses change information (diff, impact analysis) and is recalculated per commit. Model-based prioritization uses trained ML models on historical data for the highest APFD at scale. In practice, the most effective and practical approach combines version-specific ordering for changed-code cases (Tier 1) with additional-coverage-greedy ordering for unchanged-code cases (Tier 2).

Key takeaways:
  • General prioritization: stable, periodic; best for nightly regression on stable products.
  • Version-specific: dynamic, per-commit; essential for CI/CD on active development.
  • Additional coverage greedy outperforms total coverage greedy for APFD.
  • Change-Impact score CI(ti) = |cov(ti) ∩ Δ| / |Δ|; cases with CI > 0 form the version-specific P1 tier.
  • Combine both: version-specific Tchanged first; general additional-coverage for Tunchanged.
  • Model-based: only justified for suites >1,000 cases with ≥100 historical defect-labelled runs.
Assignment (Session 5.6):
  1. For your mini-project's most recent feature change, compute CI(ti) for all test cases. Report the Tchanged and Tunchanged partition sizes.
  2. Apply the combined prioritization algorithm (version-specific tier + additional coverage greedy tier) to your suite. Produce the complete ordered list.
  3. Compare your combined ordering with a FER-only ordering for the same suite. Calculate and compare the estimated APFD for each ordering (assume each test case that exercises a changed branch has a 70% probability of detecting the change-induced defect).
  4. If your team were to adopt model-based prioritization in the future, what features would you include in the model? What historical data would you need to collect starting now?