Classification Tree Method
The Classification Tree Method (CTM) is a systematic, graphical technique for designing test cases by partitioning the input domain of a test object into a tree structure and combining selections in a table. Introduced by Grochtmann and Grimm in 1993 [1], it transforms test design from an ad hoc activity into a structured, visual, and documentable process.
Why CTM?
Before CTM, the Category-Partition Method [2] used a textual formalism (TSL — Test Specification Language) to define categories, choices, and constraints. While systematic, TSL was hard to learn, produced flat lists, and generated test cases implicitly through lengthy frame expansion.
CTM addresses these limitations with three key improvements:
flowchart LR
subgraph "Category-Partition (1988)"
A1["Specification"] --> A2["TSL Text"]
A2 --> A3["Constraints"]
A3 --> A4["Generated<br>Test Frames"]
end
subgraph "Classification Tree Method (1993)"
B1["Specification"] --> B2["Tree Diagram"]
B2 --> B3["Combination<br>Table"]
B3 --> B4["Test Cases"]
end
style A1 fill:#fff3cd,stroke:#333
style A4 fill:#fff3cd,stroke:#333
style B1 fill:#c8e6c9,stroke:#333
style B4 fill:#c8e6c9,stroke:#333
| Aspect | Category-Partition | Classification Tree Method |
|---|---|---|
| Notation | Textual (TSL syntax) | Graphical (tree + table) |
| Structure | Flat list of categories | Hierarchical tree |
| Test case creation | Start large, add restrictions | Start minimal, add until sufficient |
| Specification | Implicit (lengthy generated lists) | Direct (compact combination table) |
| Hierarchy support | Complex constraints needed | Built into tree structure |
“The crucial activity during testing is test case determination, since it determines the kind and scope of the examination and thus the quality of the test.” [1]
Tree Notation
A classification tree uses four node types to model the input domain. Here is a complete example — a machine vision system that classifies figures on a conveyor belt (valid aspects only — see Modeling Invalid Cases below for the full tree with invalid exemplars):
flowchart TD
ROOT(["Machine Vision System"])
ROOT --> FIG["Figure"]
ROOT --> ENV["Environment"]
FIG --> SHAPEShape
FIG --> COLORColor
FIG --> SIZESize
SHAPE --> tri(["Triangle"])
SHAPE --> circ(["Circle"])
SHAPE --> sq(["Square"])
COLOR --> r(["Red"])
COLOR --> g(["Green"])
COLOR --> b(["Blue"])
SIZE --> sm(["Small<br>#le;300px"])
SIZE --> lg(["Large<br>#gt;300px"])
ENV --> LIGHTLighting
ENV --> BGBackground
LIGHT --> day(["Daylight"])
LIGHT --> art(["Artificial"])
BG --> white(["White"])
BG --> dark(["Dark"])
style ROOT fill:#019546,stroke:#333,color:white
style FIG fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style ENV fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style SHAPE fill:#4a90d9,stroke:#333,color:white
style COLOR fill:#4a90d9,stroke:#333,color:white
style SIZE fill:#4a90d9,stroke:#333,color:white
style LIGHT fill:#4a90d9,stroke:#333,color:white
style BG fill:#4a90d9,stroke:#333,color:white
Node Types
| Node | Visual | Meaning | Example | Test-Selectable? |
|---|---|---|---|---|
| Root | Top of tree | The test object (SUT) | Machine Vision System | No |
| Composition | Thick-bordered (green above) | “Consists of” — aggregation | Figure, Environment | No |
| Classification | Rectangle (blue above) | “Is a kind of” — partition | Shape, Color, Size | No |
| Class | Leaf node (rounded above) | Equivalence class value | Triangle, Red, Small | Yes |
Composition = “consists of” (aggregation). Classification = “is a kind of” (partition). Classes must be disjoint and complete — every possible value belongs to exactly one class.
Composition vs. Classification
The distinction is critical. Consider modeling a Car [3]:
flowchart LR
subgraph "Composition (consists of)"
C1["Car"] --> W["Wheels"]
C1 --> M["Motor"]
C1 --> CH["Chassis"]
end
subgraph "Classification (is a kind of)"
C2["Vehicle"] --> BUS["Bus"]
C2 --> TRUCK["Truck"]
C2 --> SEDAN["Sedan"]
end
style C1 fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style C2 fill:#4a90d9,stroke:#333,color:white
- A car consists of wheels, motor, and chassis — all exist simultaneously (composition)
- A vehicle is a kind of bus, truck, or sedan — exactly one applies (classification)
Modeling Invalid Cases
For robust (negative) testing, invalid inputs must be included in the classification tree. The key principle: invalid cases form a separate branch, parallel to valid aspects — they are not scattered as individual leaves within each valid classification.
flowchart TD
ROOT(["Machine Vision System"])
ROOT --> FIG["Figure"]
FIG --> INVInvalid
FIG --> VALValid
INV --> EXMP["Exemplars"]
EXMP --> hex(["Small hexagon"])
EXMP --> irreg(["Large irregular<br>shape"])
EXMP --> wclr(["Wrong color"])
VAL --> ATTR["Attributes"]
ATTR --> SHAPEShape
ATTR --> COLORColor
ATTR --> SIZESize
SHAPE --> tri(["Triangle"])
SHAPE --> circ(["Circle"])
SHAPE --> sq(["Square"])
COLOR --> r(["Red"])
COLOR --> g(["Green"])
COLOR --> b(["Blue"])
SIZE --> sm(["Small"])
SIZE --> lg(["Large"])
style ROOT fill:#019546,stroke:#333,color:white
style FIG fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style INV fill:#d32f2f,stroke:#333,color:white
style VAL fill:#019546,stroke:#333,color:white
style EXMP fill:#ffcdd2,stroke:#d32f2f,color:#333,stroke-width:3px
style ATTR fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style SHAPE fill:#4a90d9,stroke:#333,color:white
style COLOR fill:#4a90d9,stroke:#333,color:white
style SIZE fill:#4a90d9,stroke:#333,color:white
Why a separate branch? If invalid values sit inside each valid classification, they enter the combinatorial explosion — the test generator combines them with every valid value from other aspects, producing meaningless test cases like “undefined shape + red + small + bright + white.” A separate branch ensures invalids are tested individually.
Enumerate invalid cases as concrete exemplars rather than comprehensively defining them. Ask: “What specific inputs would the system reject?” The answer gives you the exemplars.
When to combine instead: If the application logic processes combinations of valid and invalid inputs together (e.g., checking multiple fields in a form), it may make sense to include invalid classes within aspects. The decision depends on how the system under test handles errors [1].
The 6-Step Process
flowchart LR
S1["1. Select<br>Test Object"] --> S2["2. Analyze<br>Aspects"]
S2 --> S3["3. Model<br>Tree"]
S3 --> S4["4. Add<br>Constraints"]
S4 --> S5["5. Generate<br>Test Cases"]
S5 --> S6["6. Export #amp;<br>Execute"]
style S1 fill:#019546,stroke:#333,color:white
style S2 fill:#2D6E2A,stroke:#333,color:white
style S3 fill:#2D6E2A,stroke:#333,color:white
style S4 fill:#fff3cd,stroke:#333,color:black
style S5 fill:#fff3cd,stroke:#333,color:black
style S6 fill:#019546,stroke:#333,color:white
| Step | Action | Key Question |
|---|---|---|
| 1 | Select test object — a function, module, or system with observable output | What are we testing? |
| 2 | Analyze aspects — identify inputs, environment conditions, and characteristics that influence behavior | What factors matter? |
| 3 | Model tree — organize aspects as compositions/classifications; partition values into disjoint classes | How do factors relate? |
| 4 | Add constraints — mark impossible combinations using dependency rules | Which combinations are infeasible? |
| 5 | Generate test cases — select one class per classification in the combination table | How many tests do we need? |
| 6 | Export & execute — assign concrete values, predict expected results, run tests | Did we find faults? |
“The Classification Tree Method is guidance for thinking, not replacement of thinking!” [3]
Example 1: City Tax Calculator
Specification: A city levies income tax as follows:
- Non-residents pay 1% of gross pay
- Residents — Single:
- Gross pay ≤ $30,000 → 1%
- Gross pay $30,001–$50,000 → 5%
- Gross pay > $50,000 → 15%
- Residents — Family:
- Gross pay ≤ $50,000 → 1%
- Gross pay > $50,000 → 5%
Step 1–3: Build the classification tree
flowchart TD
ROOT(["City Tax<br>Calculator"])
ROOT --> RESResidency
RES --> NR(["Non-Resident"])
RES --> R(["Resident"])
R --> MSMarital Status
R --> GPGross Pay
MS --> S(["Single"])
MS --> F(["Family"])
GP --> LOW(["#le; $30,000"])
GP --> MID(["$30,001–<br>$50,000"])
GP --> HIGH(["#gt; $50,000"])
style ROOT fill:#019546,stroke:#333,color:white
style RES fill:#4a90d9,stroke:#333,color:white
style MS fill:#4a90d9,stroke:#333,color:white
style GP fill:#4a90d9,stroke:#333,color:white
Step 4: Identify constraints
When Non-Resident is selected, Marital Status and Gross Pay brackets are irrelevant — they only apply to Residents. This is naturally handled by placing those classifications under the Resident class in the tree hierarchy.
Step 5: Combination table
| TC | Residency | Marital Status | Gross Pay | Expected Tax |
|---|---|---|---|---|
| 1 | Non-Resident | — | — | 1% |
| 2 | Resident | Single | ≤ $30,000 | 1% |
| 3 | Resident | Single | $30,001–$50,000 | 5% |
| 4 | Resident | Single | > $50,000 | 15% |
| 5 | Resident | Family | ≤ $50,000 | 1% |
| 6 | Resident | Family | > $50,000 | 5% |
Step 6: Concrete test cases
| TC | Residency | Status | Gross Pay | Expected Tax Amount |
|---|---|---|---|---|
| 1 | Non-Resident | — | $45,000 | $450 |
| 2 | Resident | Single | $25,000 | $250 |
| 3 | Resident | Single | $40,000 | $2,000 |
| 4 | Resident | Single | $75,000 | $11,250 |
| 5 | Resident | Family | $48,000 | $480 |
| 6 | Resident | Family | $60,000 | $3,000 |
Notice how the tree structure naturally handles the constraint: Non-Residents don’t need marital status or pay brackets. By placing those classifications under the Resident class, impossible combinations are eliminated structurally rather than with explicit rules.
Example 2: Count Function
count(searchedArray, countWhat) — counts occurrences of a value in an array.
Probing questions: Does array size matter? Does element order affect results? What about empty arrays? What if countWhat is null?
flowchart TD
ROOT(["count(array, what)"])
ROOT --> ARR["Array"]
ROOT --> CW["countWhat"]
ARR --> SZSize
ARR --> OCCOccurrences
ARR --> ORDOrder
ARR --> CNTContent Type
SZ --> sz0(["0<br>(empty)"])
SZ --> sz1(["1"])
SZ --> szN(["#gt; 1"])
OCC --> oNone(["None"])
OCC --> oOne(["One"])
OCC --> oMany(["#gt; One"])
ORD --> sorted(["Sorted"])
ORD --> unsorted(["Unsorted"])
CNT --> num(["Numeric"])
CNT --> alpha(["Alpha"])
CNT --> alnum(["Alphanumeric"])
CW --> LENLength
LEN --> empty(["Empty"])
LEN --> one(["1 char"])
LEN --> multi(["#gt; 1 char"])
style ROOT fill:#019546,stroke:#333,color:white
style ARR fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style CW fill:#2D6E2A,stroke:#333,color:white,stroke-width:3px
style SZ fill:#4a90d9,stroke:#333,color:white
style OCC fill:#4a90d9,stroke:#333,color:white
style ORD fill:#4a90d9,stroke:#333,color:white
style CNT fill:#4a90d9,stroke:#333,color:white
style LEN fill:#4a90d9,stroke:#333,color:white
Constraints (impossible combinations)
This example shows why dependency rules are essential:
| Constraint | Reason |
|---|---|
| Size = 0 → Occurrences = None | Empty array cannot contain the value |
| Size = 0 → Order is irrelevant | Cannot sort an empty array |
| Size = 1 → Occurrences ∈ {None, One} | Single element: either matches or doesn’t |
| Size = 1 → Order is irrelevant | Single element is trivially sorted |
Without constraints, the tree produces 3 × 3 × 2 × 3 × 3 = 162 combinations. Many are impossible (e.g., empty array with multiple occurrences). Constraints reduce this to a manageable and meaningful test suite.
Constraint Handling
Real systems always have impossible combinations. Constraint handling has evolved through three generations:
| Generation | Method | Example | Tool |
|---|---|---|---|
| 1st (1988) | Textual annotations | [if Resident], [error], [single] | TSL [2] |
| 2nd (2000) | Boolean dependency rules | NonResident → NOT MaritalStatus | CTE XL [4] |
| 3rd (2012) | Numerical constraints + SAT solver | a + b > c (triangle inequality) | TESTONA [5] |
Conflict Resolution Strategies
When generating test cases from a constrained tree, four strategies exist [6]:
flowchart TD
CONFLICT["Conflict<br>Detected"] --> AVOID["Avoid<br>(prevent selection)"]
CONFLICT --> REPLACE["Replace<br>(substitute value)"]
CONFLICT --> ABSTRACT["Abstract<br>(merge parameters)"]
CONFLICT --> SUBMODEL["Sub-Model<br>(split tree)"]
style AVOID fill:#c8e6c9,stroke:#388e3c,stroke-width:3px
style REPLACE fill:#fff3cd,stroke:#ffc107
style ABSTRACT fill:#fff3cd,stroke:#ffc107
style SUBMODEL fill:#fff3cd,stroke:#ffc107
The “avoid” strategy — prohibiting conflict selection during generation — produces the smallest test suites while preserving coverage criteria [6].
Tree Quality: Effectiveness Metric
Chen et al. [7] defined a metric for tree quality:
E[T] = legitimate test cases / potential test cases
- Legitimate: combinations that exist in the real input domain
- Potential: all combinations the tree can generate (including infeasible ones)
Ad hoc trees can have E[T] as low as 0.17 — meaning 83% of generated test cases are wasted on impossible combinations. Systematic restructuring can double effectiveness.
Tool Support
CTM tool support has evolved over 27+ years from a research prototype to a full test automation platform:
flowchart LR
CTE["CTE<br>(1993)"] --> CTEXL["CTE XL<br>(2000)"]
CTEXL --> PRO["CTE XL Pro<br>(2014)"]
PRO --> TESTONA["TESTONA<br>(2016+)"]
CTE -.-> F1["Graphical editor<br>Combination table"]
CTEXL -.-> F2["Dependency rules<br>N-wise generation<br>#gt;90% test reduction"]
PRO -.-> F3["BVA automation<br>Requirements tracing<br>Coverage analysis"]
TESTONA -.-> F4["SAT solver<br>Test oracles<br>Script generation"]
style CTE fill:#e1f5fe,stroke:#0288d1
style CTEXL fill:#c8e6c9,stroke:#388e3c
style PRO fill:#fff3cd,stroke:#ffc107
style TESTONA fill:#019546,stroke:#333,color:white
| Feature | CTE (1993) | CTE XL (2000) | TESTONA (2016+) |
|---|---|---|---|
| Graphical editor | ✓ | ✓ | ✓ |
| Dependency rules | — | Boolean (AND, OR, ⇒) | Boolean + Numerical |
| Test generation | Manual | Minimality, Maximality, N-wise | + SAT solver |
| Tool integration | Standalone | Server API | DOORS, HP ALM |
| Test oracles | — | — | Dependency rule-based |
| Script generation | — | — | Code fragments |
“In some cases the amount of theoretically possible test cases given by the classification tree was reduced by more than 90%” through CTE XL dependency rules [4].
Empirical Evidence
Controlled Study: CTM vs. Ad Hoc Testing
The only controlled empirical evaluation of CTM [8] studied 162 students (two groups: 104 + 58) before and after a 3-hour CTM training session:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"title": "Testing Method Preference: Before vs. After CTM Training",
"width": 400,
"height": 250,
"data": {
"values": [
{"Method": "White-box", "Phase": "Before Training", "Percentage": 53},
{"Method": "White-box", "Phase": "After Training", "Percentage": 18},
{"Method": "BVA", "Phase": "Before Training", "Percentage": 12},
{"Method": "BVA", "Phase": "After Training", "Percentage": 8},
{"Method": "EP", "Phase": "Before Training", "Percentage": 15},
{"Method": "EP", "Phase": "After Training", "Percentage": 5},
{"Method": "CTM", "Phase": "Before Training", "Percentage": 0},
{"Method": "CTM", "Phase": "After Training", "Percentage": 66},
{"Method": "Other", "Phase": "Before Training", "Percentage": 20},
{"Method": "Other", "Phase": "After Training", "Percentage": 3}
]
},
"mark": "bar",
"encoding": {
"x": {"field": "Method", "type": "nominal", "axis": {"labelAngle": 0}},
"y": {"field": "Percentage", "type": "quantitative", "title": "% of students"},
"xOffset": {"field": "Phase", "type": "nominal"},
"color": {
"field": "Phase",
"type": "nominal",
"scale": {"range": ["#fff3cd", "#019546"]}
}
}
}
| Finding | Value |
|---|---|
| Initially preferred white-box | 53% |
| Preferred CTM after 3h training | ~66% |
| Perceived CTM as systematic | 63% |
| Perceived CTM as complete | 56% |
| Original suites’ fault detection | 55% |
“None of the students’ test suites, except one developed by a mix of black and white box methods, could detect all faulty programs that our test suite derived from CTM did.” [8]
Industrial Case Studies
| Domain | Application | Finding | Source |
|---|---|---|---|
| Aerospace | Airfield lighting system | 263 test cases for 2,700 modules | Grochtmann 1993 |
| Logistics | Letter sorting machine | Halved test cases, found new errors | Grochtmann 1993 |
| Automotive | Adaptive cruise control | Embedded testing with Tessy | Buechner 2009 |
| Aviation/Space | Multiple systems | >90% test reduction via dependency rules | Lehmann 2000 |
| Automotive | Engine control, central locking | TPT for continuous behavior testing | Bringmann 2008 |
All documented industrial applications are from the Daimler/Berner & Mattner ecosystem. Independent replications outside this group are notably absent.
CTM and Other Techniques
CTM is not an isolated technique — it acts as an integrating framework that connects several test design methods:
flowchart TD
SPEC["Specification"] --> CTM["Classification<br>Tree Method"]
EP["Equivalence<br>Partitioning"] -.->|"classification<br>step"| CTM
BVA["Boundary Value<br>Analysis"] -.->|"class boundary<br>selection"| CTM
CTM -->|"combination<br>table"| COMB["Combinatorial<br>Testing"]
COMB --> TC["Test Cases"]
CTM --> TC
style CTM fill:#019546,stroke:#333,color:white
style EP fill:#c8e6c9,stroke:#388e3c
style BVA fill:#fff3cd,stroke:#ffc107
style COMB fill:#e1f5fe,stroke:#0288d1
style TC fill:#019546,stroke:#2D6E2A,color:#fff
| Technique | Relationship to CTM |
|---|---|
| Equivalence Partitioning | CTM’s classification step is equivalence partitioning |
| Boundary Value Analysis | Applied when selecting concrete values at class boundaries |
| Decision Tables | Alternative for condition-action rules; CTM better for hierarchical inputs |
| Combinatorial Testing | Pairwise/n-wise strategies applied to CTM’s combination table |
Extensions: CCTM extracts classification trees from UML activity diagrams [9], while TPT extends CTM to continuous signals in automotive systems [10].
Common Pitfalls
Based on empirical observations [8] [3]:
- Infeasible test cases (60% of novices) — use dependency rules or tree restructuring to eliminate impossible combinations
- Flat trees with no hierarchy — use composition nodes to group related aspects
- Too many classifications at root level — abstract, then refine; large trees can use sub-tree refinements
- Confusing composition with classification — ask: “consists of” (parts) vs. “is a kind of” (variants)?
- Skipping boundary values — apply BVA at class borders (e.g., $30,000 and $30,001)
- Over-specifying — keep test cases as abstract specifications; delay concrete value assignment
Key Takeaways
- CTM provides a visual, structured approach to test design — tree + combination table
- Composition vs. classification is the fundamental modeling decision
- Constraints are essential — real systems always have impossible combinations
- Start minimal, add until sufficient — unlike Category-Partition which starts large and restricts
- Tool support is mature — 27+ years of evolution from CTE to TESTONA
- CTM integrates EP, BVA, and combinatorial testing into a single framework
References
- M. Grochtmann and K. Grimm, “Classification Trees for Partition Testing,” Software Testing, Verification and Reliability, vol. 3, no. 2, pp. 63–82, 1993, doi: 10.1002/stvr.4370030203.
- T. J. Ostrand and M. J. Balcer, “The Category-Partition Method for Specifying and Generating Functional Tests,” in Communications of the ACM, 1988, pp. 676–686. doi: 10.1145/62959.62964.
- Buechner, “Test Case Design Using the Classification Tree Method.” 2009.
- E. Lehmann and J. Wegener, “Test Case Design by Means of the CTE XL,” in Proceedings of EuroSTAR 2000, 2000.
- P. M. Kruse, J. Bauer, and J. Wegener, “Numerical Constraints for Combinatorial Interaction Testing,” in Proceedings of ICST 2012, 2012. doi: 10.1109/ICST.2012.170.
- M. Grindal, J. Offutt, and J. Mellin, “Managing Conflicts When Using Combination Strategies to Test Software,” in Proceedings of the 18th Australian Software Engineering Conference (ASWEC), 2007, pp. 255–264. doi: 10.1109/ASWEC.2007.27.
- T. Y. Chen, P. L. Poon, and T. H. Tse, “An Integrated Classification-Tree Methodology for Test Case Generation,” International Journal of Software Engineering and Knowledge Engineering, vol. 10, no. 6, 2000, doi: 10.1142/S0218194000000353.
- Y. T. Yu, S. P. Ng, P. L. Poon, and T. Y. Chen, “On the Testing Methods Used by Beginning Software Testers,” Information and Software Technology, vol. 46, no. 4, 2004, doi: 10.1016/S0950-5849(03)00198-8.
- S. Kansomkeat, P. Thiket, and J. Offutt, “Generating Test Cases from UML Activity Diagrams Using the Condition-Classification Tree Method,” in Proceedings of ICSTE 2010, 2010. doi: 10.1109/ICSTE.2010.5608913.
- E. Bringmann and A. Krämer, “Systematic Testing of the Continuous Behavior of Automotive Systems,” in Proceedings of ICSE 2008, 2008. doi: 10.1145/1368088.1368127.
Disclaimer: AI is used for text summarization, polishing and explaining. Authors have verified all facts and claims. In case of an error, feel free to file an issue.