skip to content

Assertion Cost at Load

Assertions run inline on the injector thread between samples, so every regex or document parse spends generator CPU that is then not making load. Interviewers probe where you draw that line.

on this pageshow

explore

questions

5

In JMeter, when does a Response Assertion run relative to the sampler it checks?

level: juniorimportance: must knowfreq 58%

answer

  1. Nothing about it is asynchronous
  2. Same thread that issued the request
  3. After post-processors, before listeners
  4. checkAssertions sits in the sampler cycle

basics

~10 s

Straight after the sampler returns, on the very same JMeter thread. The order inside one sampler cycle is timers, the sample, post-processors, assertions, then listeners. Nothing is queued or handed to a worker pool.

solid answer

~40 s

JMeter evaluates assertions **inline**. Inside `JMeterThread`, one sampler cycle serves that element's timers, calls the sampler, runs its post-processors, calls `checkAssertions(...)`, and only then notifies the sample listeners. Every one of those steps happens on the virtual user's own thread, so an assertion is not free background work — it is injector CPU spent instead of issuing the next request. That matters as soon as the element is attached broadly: one Response Assertion scoped over a 500-thread plan runs once per sampler, per thread, per iteration, with up to 500 evaluations in flight at any instant. The check also lands *after* the sampler has stamped its own end time, so its cost never shows up in that sample's reported duration. JMeter offers no way to move an assertion off the sampler thread.

go deeper

for a junior

Recall the order: timers, sample, post-processors, assertions, listeners — all on the same thread. Saying "the assertion runs right after the response, on the thread that made the request" is the answer.

for a middle

Explain that the assertion check is a synchronous call inside the thread loop, that it happens after the sampler has already fixed its own elapsed time, and that the sample's success flag is the combined verdict listeners then see.

for a senior

Show that you count evaluations, not elements: samplers times threads times iterations, multiplied again if the assertion also visits sub-samples. That count is what turns a correctness choice into an injector capacity choice.

for a principal

Own the rule your team applies: which checks are allowed to run inside a load plan at all, and which belong in a small functional plan, so nobody has to rediscover the cost during a run.

## The order inside one sampler cycle Everything a JMeter thread does for a single sampler happens in `JMeterThread.executeSamplePackage(...)`, and the sequence is fixed: 1. **Pre-processors** for that sampler run. 2. **Timers** in scope are served — `delay(pack.getTimers())` — *before* the request goes out, not after the reply comes back. 3. **The sampler runs**. It stamps its own start and end times; `SampleResult.sampleEnd()` computes `elapsedTime` there and then. 4. **Post-processors** run, so extractors have already written their variables. 5. **`checkAssertions(...)`** runs every assertion in the sampler's package against the `SampleResult`, combining each verdict into the sample's success flag. 6. **Listeners** are notified last, and only then does the result reach a JTL writer or a GUI listener. The assertion is step 5 of 6. It is not a callback, not a queued job and not a second pass over the results file — it is a synchronous method call on the thread that just made the request. ## Why the placement is the whole point of this topic A JMeter virtual user is a real platform thread running a loop. Anything that thread does between one sample and the next is time it is not spending on the network. So the cost of an assertion is paid in the one currency an injector is short of: CPU on the load generator. Put a single Response Assertion under the Thread Group of a plan with 500 threads and eight samplers and the arithmetic is unforgiving: - it is evaluated **once per sampler**, not once per iteration, so eight times per loop; - it is evaluated **once per thread**, so 4,000 evaluations per full pass of the plan; - with 500 threads running concurrently, up to 500 of those evaluations are competing for injector cores at the same moment; - if the assertion's *Apply to* setting is `Main sample and sub-samples`, JMeter also descends into the sub-samples of each result — four levels deep — so a page sampler that retrieved forty embedded resources evaluates the same assertion forty-one times. ## What the placement does not mean Two readings of "inline" go too far and both are wrong. | Claim | Reality | |---|---| | "The assertion time is part of the response time" | No. `elapsedTime` is fixed by `sampleEnd()` inside the sampler, before the assertion is called. | | "Assertions must be cheap because JMeter runs them at the end" | No. There is no end-of-run pass; every check is paid for during the run, at load. | | "A listener evaluates the assertion" | No. Listeners receive a result that already carries its `AssertionResult` entries and its final success flag. | The corollary of the third row is worth stating plainly: because assertions run before listeners, the success flag a listener writes to the JTL is the *post-assertion* verdict. A sampler that got HTTP 200 but failed its assertion is recorded as a failure. ## Where to look when you are reasoning about it - The **element's position in the tree** tells you how many samplers it applies to. An assertion is a child of the sampler it checks, or a child of a controller or Thread Group, in which case it applies to everything below. - The **Apply to** radio decides whether sub-samples are visited as well. - The **Field to Test** radio decides how much text is handed to the check — a three-character response code or a whole response body. None of those change *when* the assertion runs. They only change how much work it does when it does run. That is the lever you actually have. ## The one-sentence version Assertions are ordinary work on the virtual user's thread, sitting between the reply and the next request, which is why "just add an assertion to every sampler" is a load-generator capacity decision and not a free correctness win.

  • Where in that cycle do post-processors such as a Regular Expression Extractor run?
    Before the assertions. JMeter calls `runPostProcessors(...)` and then `checkAssertions(...)`, so extractors have already written their variables by the time an assertion is evaluated. That is why an assertion can be pointed at a JMeter variable through its Apply to setting and still see this sample's captured value.
  • Does an assertion placed under the Thread Group run once per iteration or once per sampler?
    Once per sampler. It becomes part of every sampler package below it, and `checkAssertions` is called from the per-sampler cycle, so a plan with eight samplers evaluates it eight times in every loop of every thread. The count, not the element, is what costs you.

saying these in an interview costs you the question

  • Says assertions run on a background thread pool
  • Thinks the check happens after the run, over the results file
  • Believes assertion time is inside the sample's elapsed value
  • Claims a listener performs the assertion
  • Assumes one assertion element means one evaluation per iteration
open as a page

In a 500-thread JMeter plan, adding a Response Assertion to every sampler left response times flat but cut throughput. Why?

level: seniorimportance: must knowfreq 52%

basics

~20 s

The sampler stamps its own end time before the assertion runs, so the check sits outside the reported duration. It is still inside the thread's loop, so each thread gets through fewer samples per second.

open as a page

In a JMeter Response Assertion scanning a 200 KB body, why is Substring cheaper than Contains?

level: middleimportance: should knowfreq 47%

basics

~10 s

Substring is a plain literal scan of the text. Contains hands the whole body to a Perl5 regular-expression matcher instead. Same text, much more work per sample, repeated on every sample every thread makes.

open as a page

In JMeter, how would you keep deep response validation out of a 500-thread load plan?

level: principalimportance: should knowfreq 41%

basics

~10 s

Put the deep checks in a small separate Thread Group or a separate functional plan, and leave the 500-thread group with cheap checks such as a Response Assertion on the response code.

open as a page

In JMeter, what does an XML Schema Assertion do on every sample that a Response Assertion does not?

level: seniorimportance: nice to knowfreq 33%

basics

~20 s

It parses the whole response as an XML document and validates it against the schema file, building a fresh validating JAXP parser for each sample. A Response Assertion only walks the text. The parse is the expensive part.

open as a page