Testland

HTSM: Inside James Bach's Heuristic Test Strategy Model

TestlandAugust 1, 2026

HTSM is James Bach's four-branch model for test strategy, currently v6.3: test techniques, project elements, product factors, and quality criteria categories.

HTSM's four focus areas as published in v6.3 (December 2024): test techniques, project elements, product factors, and quality criteria categories. Quality criteria categories, highlighted, is the only one of the four whose name survived unchanged from v5.2 in 2013.

A backlog ticket reads "test CSV import." Nothing else: no charter, no risk notes, no hint about which of a dozen plausible failure modes matters most. A tester facing that line either tests everything at once, shallow and unfocused, or follows a single instinct (try a huge file, maybe) and never finds out what else was worth checking.

HTSM is James Bach's Heuristic Test Strategy Model, and it answers that with four branches to think through before a charter gets written: test techniques, project elements, product factors, and quality criteria categories. Running it well means picking the one or two that matter for the charter in hand, not working through all four exhaustively every session. Those four names come from the current edition, version 6.3, published December 2, 2024, and three of them changed after the version most explainers still quote. Bach's own description: "The HTSM (v.6.3) is a set of guideword heuristics designed to help you think better about test strategy" (satisfice.com, December 2024). It's one heuristic model inside Rapid Testing Methodology, not a synonym for it: RST's own page states "The RST Methodology includes many heuristic models designed to help structure your work" (satisfice.com). The same v6.3 document adds that it isn't exploratory-testing-specific: "It is pretty generic to any kind of software."

This post assumes you've done hands-on exploratory testing, know what a test charter and a session are, and are comfortable with the idea of a testing heuristic - a fallible rule of thumb, not an algorithm.

  • Current version: v6.3, published December 2, 2024.
  • The four branches: test techniques, project elements, product factors, and quality criteria categories.
  • "You can use it casually or rigorously."
  • HTSM sits inside Rapid Testing Methodology (RST) as one heuristic model among several, not a synonym for the whole methodology.

What testers do when a charter has no starting point

A tester who's never touched HTSM defaults to one of two failure modes when a charter is this thin. The first is breadth without focus: open the import screen, upload a couple of files, click through the UI, and call it tested once nothing obviously breaks. The second is depth without breadth: fixate on one plausible risk (a huge file, say) and never notice the several other risks sitting untested in the same feature.

Both failure modes trace back to the same root cause: no reference set for what to consider. That's the gap HTSM fills, but not by handing over a script. The context-driven premise underneath it is that test strategy is a matter of skilled judgment applied to a specific context, not compliance with a fixed procedure that produces the same steps regardless of what's being tested. HTSM is built to match: a set of things to consider, not a sequence to execute top to bottom on every charter.

Bach states the flexibility directly: "You can use it casually or rigorously." A tester triaging a five-minute bug report might silently check one or two guideword prompts from memory. A tester scoping a two-hour session on an unfamiliar feature might work through a branch in writing, prompt by prompt. Both are legitimate uses of the same document.

The model also isn't meant to be adopted verbatim. Bach: "I'd encourage you to modify this to fit the context of your own organization." The guidewords are prompts for a tester's own thinking, not a checklist to fill out and file. Skipping most of a branch on a given charter isn't misuse: it's the intended mode.

Why most HTSM explainers still use outdated branch names

Attribution: James Bach and the current v6.3 edition

HTSM is James Bach's model. He's the tester who developed Rapid Testing Methodology and has maintained the HTSM document under his own name for years, publishing revisions on satisfice.com as his thinking on test strategy changed. The current edition is version 6.3, published December 2, 2024, and it's the version this post works from throughout: Heuristic Test Strategy Model, satisfice.com.

That attribution matters because HTSM circulates widely in slide decks, training materials, and blog posts that don't always cite a version number. A branch name copied from an old training deck can silently drift from what the current document actually says, and a tester citing "Product Elements" as current HTSM terminology is citing a name Bach retired years ago.

What changed between v5.2 (2013) and v6.3 (2024)

An earlier edition, version 5.2, dated 23 June 2013, used different names for three of the four branches. The current v6.3 document states: "It includes four focus areas: test techniques, project elements, product factors, and quality criteria categories" (satisfice.com).

Current name (v6.3)Earlier name (v5.2, 2013)
Test techniquesGeneral Test Techniques
Project elementsProject Environment
Product factorsProduct Elements
Quality criteria categoriesQuality Criteria Categories

"General" dropped from the techniques branch, "Environment" became "elements" on the project side, and "Elements" on the product side became "factors." Quality criteria categories is the one branch name that hasn't changed since 2013.

One honest caveat: the v5.2 wording above doesn't survive on satisfice.com anymore. It's preserved only on third-party mirrors of the older document, not on an official page. Treat the v5.2 column as historical record, not as something citable as current Bach terminology.

One feature: bulk CSV import for a task tracker

The rest of this post runs one invented feature through all four HTSM branches: not a real customer, a constructed example built to show how the branches change what a tester notices.

A project-management SaaS product lets teams import tasks in bulk from a CSV file, capped at 5,000 rows per file. The backlog ticket assigned to QA reads exactly this: "test CSV import." No charter, no acceptance criteria beyond the row cap, no notes on which failure modes the team already worries about.

That's the same starting point as the opening scenario: one line, several plausible directions, no obvious place to start. The next four sections run that one line through test techniques, project elements, product factors, and quality criteria categories in turn, and compare what each branch surfaces that the blank ticket didn't.

Running one feature through HTSM's four branches

HTSM's four branches are guideword categories, not a fixed sequence: a tester with limited time might run only one or two, chosen for what the charter actually needs. This post runs all four for teaching purposes, to show what each contributes on its own. Test techniques covers how to test; project elements covers the constraints around the work; product factors covers what's actually being tested; quality criteria categories covers what "working" means.

Test techniques: which tactics does a 5,000-row limit call for?

Test techniques is the branch that asks which testing tactics apply to this specific feature, not which ones a tester defaults to out of habit. For a row-capped CSV import, three tactics surface immediately.

Domain and boundary testing points straight at the 5,000-row cap: a file with exactly 5,000 rows, one with 5,001, and one with 4,999 test whether the limit is enforced where the spec says it is. The zero-row boundary matters just as much: an empty file, headers only or genuinely blank, is a boundary a tester chasing the upper limit can easily forget.

Combination testing points at everything that can vary independently within a valid file: delimiter (comma vs semicolon, common in exports from European locales), text encoding (UTF-8 vs Windows-1252), and line-ending style (LF vs CRLF). Any two of those combined in one file is a case the row-boundary tests alone won't touch.

Risk-based prioritization decides what gets tested in the first hour versus the fourth: a tester with one session picks the boundary and one encoding mismatch first, because a silent data-corruption bug on a common export format outranks a rare delimiter edge case.

Project elements: does staging enforce the same import limit as production?

Project elements is the branch that asks about the constraints around the testing work itself, separate from the product under test. Four questions apply directly here.

Mission and deadline: is this charter a quick sanity check before a release freeze tomorrow, or a thorough pass with a week available? The answer changes which test-techniques ideas above actually get run.

Staff and skill: does whoever picks up this charter know how to generate a malformed CSV on purpose (wrong encoding, embedded commas, ragged rows), or does testing stop at whatever file happens to be lying around?

Test environment: does staging enforce the same 5,000-row limit as production, or is the cap only wired up in one environment? A limit that's soft in staging and hard in production means the boundary tests above pass in the wrong place and mean nothing.

Deliverables: what does the debrief at the end of the session need to report? A pass/fail note on the row cap is a different deliverable than a list of every encoding combination tried, and the charter should say which one is expected before the session starts.

Product factors: where a CSV parser meets real spreadsheet exports

Product factors is the branch that asks what's actually being tested, broken into whatever categories fit the product. A guideword set commonly associated with this branch, though not confirmed in Bach's own published wording, is SFDPOT: Structure, Function, Data, Platform, Operations, Time. Applied to the CSV import feature, each letter surfaces a different question.

The encoding and delimiter variants that surfaced under test techniques land here too, but as questions about the product rather than about tactics. Structure is the CSV parser itself: what library handles the file, and does it fail loudly or silently on a malformed row. Function is the sequence of parse, deduplicate, and create: does the import check for existing tasks with the same title before creating duplicates, and what happens to a row that parses but fails validation partway through.

Data is encoding and malformed rows specifically: a UTF-8 file with a byte-order mark, a row with an extra unescaped comma inside a quoted field, a row missing a required column entirely. Platform is the browser upload path: does a 5,000-row file, potentially several megabytes, upload the same way in every supported browser.

Operations is how teams actually generate the file in practice, not how the spec assumes they will: most CSV exports for this kind of import come out of a spreadsheet program, and spreadsheet exports routinely introduce stray commas, inconsistent quoting, and locale-specific delimiters that a hand-crafted test file wouldn't include. Time is the sync delay: does the UI show the import as complete before every one of 5,000 rows is actually committed and visible.

Quality criteria categories: what has to hold for an import to count as working?

Quality criteria categories is the branch that asks what "working" actually means for this feature, beyond "it doesn't crash." A mnemonic commonly associated with this branch, again without a confirmed primary quote from Bach, is CRUSSPIC STMPL, whose letters expand to quality categories such as capability, reliability, usability, scalability, security, and performance, among others. Four of those carry the most weight for a CSV import.

Performance: how long does a 5,000-row import actually take, and does the UI communicate progress during that time or leave the user staring at a spinner with no indication whether the import is still running or has stalled.

Reliability: what happens on partial failure, when row 3,000 of 5,000 fails validation. That row is exactly the kind of malformed input the product factors pass predicted a spreadsheet export would produce, so this branch turns that prediction into a question about behavior: does the import roll back everything, commit everything before the failure and report which rows succeeded, or leave the data in a state nobody can easily audit.

Usability: when a row is malformed, does the error message say which row and what's wrong with it, or return a generic "import failed" that leaves the user re-checking all 5,000 rows by hand.

Security: if a task title or description from the CSV contains a leading =, +, -, or @ character, an imported value later re-exported to CSV and opened in a spreadsheet program can execute as a formula, a known formula-injection risk in any CSV-in, CSV-out feature.

Each of these is a different way "the import works" can be true or false, and none of them show up if the only test run is "upload a valid file and confirm the tasks appear."

What four branches surfaced that a blank charter wouldn't

Run side by side, the four branches don't overlap much, and each contributes one idea the blank "test CSV import" ticket didn't contain on its own.

Test techniques contributed the boundary set: 4,999, 5,000, 5,001, and zero rows, plus at least one delimiter and encoding combination. Project elements contributed a scope question the ticket never answered: whether staging enforces the same cap as production, and what the debrief needs to report back. Product factors contributed the operations angle: real spreadsheet exports, not hand-crafted test files, are the actual input this feature needs to survive. Quality criteria categories contributed the two failure modes most likely to matter in production: what a partial failure at row 3,000 leaves behind, and whether an imported value can execute as a formula on re-export.

The payoff isn't a longer test list: it's a sharper one. A charter built from this pass targets the row-boundary and partial-failure path specifically, instead of a generic "try importing a file" pass. That's the same move as turning a surfaced risk into a scoped session: name the risk, then charter a session around it.

Where HTSM's judgment call still lands on the tester

HTSM is a heuristic, not an algorithm, and that's a limitation as much as a feature. Running all four branches on the CSV import example produced a longer, sharper list of test ideas than the blank ticket did. It didn't produce a provably complete one. A heuristic is fallible by design: it helps a tester think better about strategy, it doesn't guarantee the resulting strategy covers every risk that matters.

HTSM also doesn't rank the branches for you. Nothing in the document says test techniques matters more than product factors on a given charter, or that quality criteria categories can wait until the second session. That call is the tester's, made from context: deadline pressure, what broke last time, which stakeholder is asking. Two testers running the same charter through the same four branches can reasonably walk away with different priority orders, and both can be defensible.

One more judgment call sits upstream of all of those: which version of the model a tester is working from, and whose document it actually is. Tester Dan Ashby published an independent extension in December 2017, describing his own process: "I began drafting a new model, based on the HTSM" (danashby.co.uk, December 2017). Ashby's version is explicitly his own work built on top of HTSM, not an official Bach revision, and it's worth flagging as a separate document for exactly that reason: the same attribution discipline that separates v5.2 wording from v6.3 wording applies to separating Bach's document from a practitioner's derivative of it.

None of that makes HTSM less useful. It just means the model hands a tester a wider set of things to consider, not a verdict.

What changes when a charter names the branch

The payoff shows up in how a charter reads to someone reviewing it, not in a theory of test strategy. "Test CSV import" tells a reviewer nothing about scope. "Test techniques: row-boundary and encoding combinations; quality criteria: partial-failure behavior at row 3,000" tells a reviewer exactly what's in scope and, by omission, what isn't, the same legibility a 60-second debrief gives a session's results. Naming the branch a test idea came from makes a charter's scope defensible the same way naming an oracle makes a bug call defensible: the reviewer now has a specific reference point to check against, not a feeling that testing happened. The current document is worth reading in full: Heuristic Test Strategy Model (v6.3), satisfice.com.