---
title: "06 — The Test Types Landscape — Scope, Intent, and Timing"
uid: test-types-landscape
tags: ["roadmap:qa", "smoke", "exploratory", "integration", "uat", "sanity", "non-functional", "stress", "regression", "unit", "performance", "functional"]
excerpt: "Every test type is a slice across two axes — scope (how much of the system runs) and intent (what question the test asks). The dozens of names collapse onto that grid."
date: 2026-08-13T03:27:48+0000
source: https://www.aveshina.my.id/en/blog/test-types-landscape
---

"Vocabulary to memorize for a certification" was my test-types model, and the names stayed noise until I found the structure underneath. The insight that revealed it: **every test type is a slice across two axes — scope (how much of the system runs during the test) and intent (what question the test is asking) — and the dozens of names collapse onto that grid** [1]. "Unit," "integration," "smoke," "regression," "stress," "UAT" aren't a flat list; they're positions on a 2D map, and once I saw the map, the names stopped feeling arbitrary.

The framing that landed is that each test type answers a different question. "Does this function work?" (unit), "do these modules talk to each other?" (integration), "is the build even alive?" (smoke), "did my change break something that worked?" (regression), "can it survive real traffic?" (load/performance), "will a real user accept this?" (UAT), "what haven't I thought of?" (exploratory). A test suite is a portfolio of bets across these questions, and the art is holding the right balance rather than over-investing in any one.

## The two-axis map

```figure
<svg viewBox="0 0 740 380" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="A 2D grid mapping test types. X-axis: scope, from Unit on the left to System on the right. Y-axis: intent, four bands bottom-to-top: 'does it work?', 'does it still work?', 'does it survive load?', 'will users accept it?'. Dots placed in cells: Unit and Mocking bottom-left; Integration lower-mid; Smoke and Sanity just right of mid on the 'is it alive' band; Regression spanning 'does it still work'; Load, Stress, Performance on the 'survive load' band; UAT and Exploratory top-right.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- axes -->
    <line x1="120" y1="40" x2="120" y2="340" stroke="#475569" stroke-width="1.5"/>
    <line x1="120" y1="340" x2="700" y2="340" stroke="#475569" stroke-width="1.5"/>

    <!-- y labels (intent) -->
    <text x="112" y="70" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">will users</text>
    <text x="112" y="83" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">accept it?</text>
    <text x="112" y="140" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">does it survive</text>
    <text x="112" y="153" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">load?</text>
    <text x="112" y="220" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">does it still</text>
    <text x="112" y="233" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">work?</text>
    <text x="112" y="305" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="end">does it work?</text>

    <!-- x labels (scope) -->
    <text x="180" y="358" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">unit</text>
    <text x="320" y="358" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">integration</text>
    <text x="480" y="358" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">system</text>
    <text x="640" y="358" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">user-facing</text>

    <!-- dots -->
    <g font-size="10" font-weight="700" text-anchor="middle">
      <!-- does it work -->
      <circle cx="180" cy="300" r="7" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
      <text x="180" y="285" fill="#052e16">Unit</text>
      <circle cx="230" cy="300" r="7" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
      <text x="230" y="285" fill="#052e16">Mocking</text>
      <circle cx="320" cy="300" r="7" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
      <text x="320" y="285" fill="#052e16">Integration</text>

      <!-- does it still work -->
      <circle cx="230" cy="225" r="7" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
      <text x="230" y="210" fill="#422006">Smoke</text>
      <circle cx="305" cy="225" r="7" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
      <text x="305" y="210" fill="#422006">Sanity</text>
      <circle cx="420" cy="225" r="7" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
      <text x="420" y="210" fill="#422006">Regression</text>

      <!-- survive load -->
      <circle cx="380" cy="150" r="7" fill="#fee2e2" stroke="#dc2626" stroke-width="1.5"/>
      <text x="380" y="135" fill="#7f1d1d">Load</text>
      <circle cx="455" cy="150" r="7" fill="#fee2e2" stroke="#dc2626" stroke-width="1.5"/>
      <text x="455" y="135" fill="#7f1d1d">Stress</text>
      <circle cx="540" cy="150" r="7" fill="#fee2e2" stroke="#dc2626" stroke-width="1.5"/>
      <text x="540" y="135" fill="#7f1d1d">Performance</text>

      <!-- will users accept -->
      <circle cx="560" cy="75" r="7" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="560" y="60" fill="#1e1b4b">UAT</text>
      <circle cx="640" cy="75" r="7" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
      <text x="640" y="60" fill="#1e1b4b">Exploratory</text>
    </g>
  </g>
</svg>
```

Reading the grid: the bottom band ("does it work?") is where the developer spends most of their time — unit tests, integration tests, the daily verification that the code does what it says. The second band ("does it still work?") is regression's home — the gate that catches change-induced breakage. The third ("does it survive load?") is performance territory. The top ("will users accept it?") is the human-judgment band that automation can't touch. Every test I write sits somewhere on this map, and the question I ask of any suite is "which cells are empty?"

## The bottom band: scope-based testing

The vertical axis the roadmap cares most about is **scope** — how much of the system runs during the test. This is the classic test pyramid, and the roadmap's nodes map onto it directly:

- **Unit testing** isolates the smallest possible piece — a function, a method — and verifies it in isolation [2]. Fast, numerous, narrow. This is where mocking lives (more on that below).
- **Integration testing** takes several modules that were built separately and tests them *together* — does the data flow between them correctly? [3] Slower, fewer, wider. Most real defects live at the seams between modules, which is why a suite of only unit tests gives false confidence.
- **System / end-to-end testing** runs the whole application, through the real browser or real API, simulating a user. Slowest, fewest, widest. These catch environment and wiring bugs that lower levels miss, but their slowness means you can't afford many.

The pyramid metaphor (many unit, fewer integration, fewest end-to-end) is a cost-speed tradeoff, not a moral hierarchy. Each scope catches a different class of defect, and a healthy suite has all three.

## Functional versus non-functional

Cross-cutting the scope axis is the **intent** split between functional and non-functional testing [4][5]:

- **Functional testing** validates the system against functional requirements — does it *do* what it's specified to do? Login works, cart totals correctly, form submits. The output is checked against the spec.
- **Non-functional testing** validates the *qualities* — reliability, performance, security, usability. Not "does it work" but "how well does it work, under what conditions, for whom."

The roadmap makes a sharp point: non-functional parameters are *never tested before functional testing* [5]. There's no point load-testing a system that doesn't even work correctly at one user. Functional is the prerequisite; non-functional is the refinement.

## The "does it still work?" band: build-confidence tests

This band holds three tests that all answer "should we even proceed?" but at different granularities:

- **Smoke testing** is the minimal set run on every build to confirm the build is stable enough to test further [6]. If smoke fails, you reject the build and don't waste time on deeper tests. It's the "is it alive?" check.
- **Sanity testing** is the narrower cousin — run after a *minor* code change to confirm the specific fix works and didn't introduce obvious new issues [7]. If sanity fails, the build is rejected before deeper regression.
- **Regression testing** re-executes existing test cases to confirm a recent change hasn't broken previously-working functionality [8]. This is what automation is best at, because the cases are known and stable and need to run on every change.

The distinction between smoke and sanity trips people up. Smoke is shallow-and-wide ("are the major paths alive?"); sanity is narrow-and-focused ("did this specific fix work?"). Both are gates that save the team from wasting a full test cycle on a broken build.

## The "survive load?" band: performance testing

**Performance testing** is the umbrella, and the roadmap breaks it into sub-types that differ by *what kind* of load [9][10]:

- **Load testing** applies expected real-life load and measures behavior [11]. "Can it handle our normal peak?"
- **Stress testing** pushes beyond normal capacity to find the breaking point and observe how it fails [12]. "What happens when we exceed it?"
- **Spike testing** (a sub-type the roadmap's resources call out) applies sudden sharp surges. "Can it absorb a traffic spike?"
- **Endurance / soak testing** applies sustained load over a long period to surface memory leaks and degradation.

The shared output is metrics — response times (p95, p99), throughput, error rates — measured against service-level objectives. Performance testing without defined SLOs is just generating numbers.

## The "will users accept it?" band: human judgment

The top band holds the tests automation can't replace:

- **UAT (User Acceptance Testing)** is performed by the actual end user or client, in the final phase, to accept or reject the software before production [13]. It's the validation step from my manual-testing notes — "are we building the right product?" — answered by the person who has to use it.
- **Exploratory testing** is simultaneous learning, test design, and test execution — the tester investigates the product, designing tests on the fly based on what they observe [14]. It's where the cases nobody wrote down get discovered. The roadmap's resources treat it as a first-class discipline with its own definitions and history, not as ad-hoc clicking.

These two are the unautomatable safety net. UAT catches the "built the wrong thing" failure; exploratory catches the "nobody thought to test this edge case" failure.

## Mocking: the enabler of isolation

The roadmap's **Mocking** node belongs in the scope discussion because it's the technique that makes unit tests *unit* tests [15]. A mock is a simulated object that mimics a real dependency — a database, an API, another service — so the code under test can be exercised without the real dependency being available, slow, or stateful.

```
// the real dependency: a database that needs a network and persists state
// the mock: a fake that returns canned data, instantly, in-memory

// without mocking: unit test becomes an integration test by accident
// with mocking: the unit is tested in true isolation
```

The tradeoff is that mocks decouple the test from the real dependency's behavior — if the mock doesn't faithfully mimic the real thing, the test passes but the integration breaks. That's the seam integration tests exist to cover. Mock aggressively at the unit level; verify the real interactions at the integration level.

## Security testing as a cross-cutting concern

The roadmap lists **Security Testing** as a node in this sprawl, and it's worth flagging that security is really its own vertical — it has its own dedicated post later in this series. For this map, security sits as a non-functional intent ("can it be attacked?") that applies at every scope: unit-level input validation, integration-level auth flows, system-level penetration testing. It's listed here to acknowledge it; the depth lives in the security post.

## How I use this

The practical payoff is a portfolio question I ask of any test suite: **which cells on the map are empty, and is that emptiness deliberate?**

- A team with only unit tests has a false-confidence problem — the seams are untested.
- A team with only end-to-end tests has a speed problem — the suite takes an hour and nobody runs it locally.
- A team with no regression tests has a "we keep breaking the same thing" problem.
- A team with no exploratory or UAT has a "we built the wrong thing beautifully" problem — verification strong, validation absent.

The aim isn't to fill every cell; it's to know which cells you're consciously leaving empty and why. Test types aren't a checklist to complete — they're a portfolio to balance, and the balance shifts with the project's risk profile.

## References

[1] Elprocus, "What are testing techniques: types, advantages & disadvantages," 2023. [Online]. Available: [https://www.elprocus.com/what-are-testing-techniques-types-advantages-disadvantages/](https://www.elprocus.com/what-are-testing-techniques-types-advantages-disadvantages/)

[2] Guru99, "Unit testing tutorial," 2023. [Online]. Available: [https://www.guru99.com/unit-testing-guide.html](https://www.guru99.com/unit-testing-guide.html)

[3] Guru99, "Integration testing tutorial," 2023. [Online]. Available: [https://www.guru99.com/integration-testing.html](https://www.guru99.com/integration-testing.html)

[4] BrowserStack, "What is non-functional testing," 2023. [Online]. Available: [https://www.browserstack.com/guide/what-is-non-functional-testing](https://www.browserstack.com/guide/what-is-non-functional-testing)

[5] BrowserStack, "Functional testing: a detailed guide," 2023. [Online]. Available: [https://www.browserstack.com/guide/functional-testing](https://www.browserstack.com/guide/functional-testing)

[6] Evaluat, "Smoke testing vs performance testing," 2024. [Online]. Available: [https://www.evaluat.com/blog/smoke-testing-vs-performance-testing](https://www.evaluat.com/blog/smoke-testing-vs-performance-testing)

[7] BrowserStack, "What is sanity testing?," 2023. [Online]. Available: [https://www.browserstack.com/guide/sanity-testing](https://www.browserstack.com/guide/sanity-testing)

[8] Katalon, "What is regression testing? Definition, tools and examples," 2023. [Online]. Available: [https://katalon.com/resources-center/blog/regression-testing](https://katalon.com/resources-center/blog/regression-testing)

[9] Evaluat, "What is performance testing? A QA engineer's guide," 2024. [Online]. Available: [https://www.evaluat.com/blog/what-is-performance-testing](https://www.evaluat.com/blog/what-is-performance-testing)

[10] Evaluat, "Load vs stress vs performance testing," 2024. [Online]. Available: [https://www.evaluat.com/blog/load-vs-stress-vs-performance-testing](https://www.evaluat.com/blog/load-vs-stress-vs-performance-testing)

[11] Evaluat, "Real-browser load testing, explained," 2024. [Online]. Available: [https://www.evaluat.com/blog/real-browser-load-testing](https://www.evaluat.com/blog/real-browser-load-testing)

[12] Evaluat, "Stress testing a website: find the breaking point," 2024. [Online]. Available: [https://www.evaluat.com/blog/stress-testing-a-website](https://www.evaluat.com/blog/stress-testing-a-website)

[13] Guru99, "What is User Acceptance Testing (UAT)?," 2023. [Online]. Available: [https://www.guru99.com/user-acceptance-testing.html](https://www.guru99.com/user-acceptance-testing.html)

[14] Satisfice, "Exploratory testing," 2024. [Online]. Available: [https://www.satisfice.com/exploratory-testing](https://www.satisfice.com/exploratory-testing)

[15] Microsoft, "Mocking in unit tests — engineering playbook," 2024. [Online]. Available: [https://microsoft.github.io/code-with-engineering-playbook/automated-testing/unit-testing/mocking/](https://microsoft.github.io/code-with-engineering-playbook/automated-testing/unit-testing/mocking/)

```quiz
Q: The two axes that organize all the test-type names are…
- cost and speed
- scope (how much of the system runs) and intent (what question the test is asking)
- language and framework
correct: 1
explain: Unit/integration/system are scope positions. 'Does it work / does it still work / does it survive load / will users accept it' are intents. Every test type sits at a cell on this 2D map.

Q: Smoke testing and sanity testing both gate a build, but they differ in…
- nothing; they are the same test
- smoke is shallow-and-wide ('are major paths alive?'); sanity is narrow-and-focused ('did this specific fix work?')
- smoke is automated; sanity is always manual
correct: 1
explain: Smoke runs the broad minimal set on every build. Sanity runs after a minor change to confirm the specific fix. Both reject the build on failure, but at different granularities.

Q: Why are non-functional parameters 'never tested before functional testing'?
- because non-functional tests are slower
- because there's no point load-testing a system that doesn't even work correctly at one user
correct: 1
explain: Functional correctness is the prerequisite. Load-testing a broken login tells you nothing useful. Non-functional testing refines an already-working system.

Q: Mocking makes unit tests 'unit' tests by…
- running them faster with better hardware
- replacing real dependencies (databases, APIs) with simulated objects so the unit runs in true isolation
- adding more assertions
correct: 1
explain: A mock mimics a dependency with instant, canned behavior. The tradeoff: if the mock doesn't faithfully mimic the real thing, the test passes but integration breaks — which is why integration tests exist.

Q: A team has only unit tests and no integration or exploratory tests. The most likely failure mode is…
- tests run too slowly
- defects at the seams between modules go uncaught, and 'nobody thought to test this' edge cases are missed
- the team can't deploy
correct: 1
explain: Unit tests give false confidence because most real defects live at module seams. Without integration tests the seams are untested; without exploratory testing, unwritten cases go undiscovered. The portfolio is unbalanced.
```
