skip to content

Async Verification (timeout)

verify(mock, timeout(ms)) polls until the interaction happens on another thread, while after(ms) waits the full duration to assert it did or didn't. The timeout-vs-after distinction is the standard question for testing callback- and executor-driven code.

on this pageshow

questions

5

In a Mockito test the collaborator is invoked from a background thread, so a plain verify() runs before the call happens. How does verify(mock, timeout(1000)).method() solve that, and what is Mockito doing during that second?

level: middleimportance: must knowfreq 45%

answer

  1. polls every ~10 ms
  2. returns on first success = upper bound
  3. times/atLeast/only yes, never no
  4. counts all calls since mock creation
  5. better than sleep, worse than a latch

basics

~20 s

timeout(ms) wraps the verification mode in a retry loop: Mockito re-checks the mock's recorded calls about every 10 ms until the check passes or the budget expires, then rethrows the last failure. It returns the moment it succeeds, so the number is an upper bound, not a sleep.

solid answer

~50 s

A plain verify(mock) queries the mock's invocation list once, immediately, on the test thread, so when work is handed to an executor or listener thread you get 'Wanted but not invoked'. verify(mock, timeout(1000)).method() wraps the normal mode in a polling loop: Mockito re-runs the check every ~10 ms until it passes or 1000 ms elapse, then rethrows the last failure. It returns as soon as the verification succeeds, so the value is an upper bound — a generous 2 s timeout costs nothing on the happy path and only slows genuine failures. It composes with positive modes: timeout(1000).times(2), .atLeast(2), .atLeastOnce(), .only(). Negative modes such as never() are rejected; those need after(ms). It beats Thread.sleep() before verify, but it is still wall-clock waiting — a latch or a synchronous executor is more deterministic when the design allows it.

code

java · 7 lines
java
@Test
void publishesEventAsynchronously() {
    service.submit("payload"); // hands off to an ExecutorService

    verify(listener, timeout(2000)).onEvent("payload");
    verify(listener, timeout(2000).times(2)).onEvent(any());
}

go deeper

for a junior

Know that plain verify checks immediately and that timeout(ms) waits up to that long for the call to show up, instead of Thread.sleep.

for a middle

Explain the polling loop, the fail-fast-on-success property, the modes it composes with, and why the timeout is an upper bound rather than a delay.

for a senior

Add that counts are cumulative, that a swallowed worker exception masquerades as a verification timeout, and when a latch or synchronous executor is the better fix.

for a principal

Frame it as a policy: timeouts are acceptable at integration seams where asynchrony is the behaviour under test, but a unit test needing them usually lacks an injectable execution seam.

## Why a plain verify fails A mock records every call made to it. verify(mock).send("x") is not a subscription and not a wait: it is one immediate query against that recorded list, evaluated on the calling thread. When the code under test hands work to an ExecutorService, an @Async method, or a message listener, the test thread reaches verify while the worker has not run yet, so zero matching invocations exist and Mockito throws 'Wanted but not invoked'. The failure is timing-dependent, which is why such tests often pass on a fast laptop and fail on loaded CI — or the reverse. ## What timeout() actually does Mockito.timeout(millis) returns a verification mode that decorates the real one (times(1) unless you say otherwise). Its verify step runs a loop: attempt the wrapped verification; on success return immediately; on failure sleep a short polling interval (10 ms in Mockito's implementation) and try again; when the clock runs out, rethrow the most recent assertion error. So the semantics are 'wait up to N milliseconds for this interaction to appear'. Two consequences follow. First, timeout is fail-fast on success: the happy path costs only as long as the code actually takes, so choosing 2000 instead of 200 does not slow a passing suite. Second, the cost of a large timeout is paid only by failing tests, which argues for generous values rather than tight ones. ## Which modes it composes with timeout(ms) accepts positive expectations: times(n), atLeastOnce(), atLeast(n), only(). Each is retried as a whole, so timeout(500).times(2) returns the instant the second matching call is recorded. Negative expectations do not work: Mockito rejects timeout(...).never() with a friendly-reminder exception, because a not-yet-happened call is indistinguishable from a never-happening one at t=0; use after(...).never() instead. ## Counting is cumulative Verification always counts every matching invocation recorded on that mock since it was created (or last reset), not only those arriving during the wait. A timeout(500).times(1) that polls just after the first of two calls can return green before the second arrives — the same test can fail on a different run when both calls land first. If exact counts matter under concurrency, prefer after(ms).times(n), which waits the full window. ## Cross-thread mechanics Mockito's invocation container is synchronised, so calls recorded by a worker thread are visible to a verifying test thread. What is not safe is stubbing from one thread while another invokes the mock. Also, an exception thrown inside the worker is usually swallowed by the executor; the symptom you see is a timeout failure, so always check the future or an error handler before blaming Mockito. ## Where it sits among alternatives timeout() is strictly better than sleeping before verify: shorter on success, more explicit in intent. It is still weaker than making the test deterministic — injecting a same-thread executor, awaiting a CountDownLatch the mock's answer counts down, or using Awaitility to poll a real observable state. Use timeout() when the asynchrony is inherent to what you are testing, not to paper over a missing seam.

  • Does a big timeout value slow down a passing test suite?
    No. The loop returns the instant the wrapped verification passes, so a passing test costs only the real latency of the async work. The full budget is spent only when the interaction never arrives, i.e. on a failing test. That asymmetry is the argument for generous timeouts (seconds) instead of tight ones (tens of milliseconds).
  • Your async task throws inside the executor and the mock is never called. What does the test report?
    It reports a Mockito 'Wanted but not invoked' failure after the full timeout, with no hint of the real exception, because most executors capture the throwable in the Future and drop it otherwise. Assert on the Future or install an uncaught-exception handler / error callback so the true cause surfaces instead of a misleading verification failure.

Refreshing a parcel-tracking page every few seconds until it says delivered, with a rule that you give up after five minutes — you stop the moment it arrives, not after the full five.

saying these in an interview costs you the question

  • Saying timeout(1000) always waits a full second, like a sleep
  • Thinking timeout retries the *call* under test rather than re-running the verification
  • Assuming timeout only counts invocations that arrive after verify was called
  • Claiming timeout(...).never() is a valid way to assert nothing happened
  • Using a 20-50 ms timeout 'to keep the suite fast' and then blaming CI for flakiness

context

open as a page

Mockito offers both verify(mock, timeout(200)).send(msg) and verify(mock, after(200)).send(msg). How does each one spend those 200 milliseconds, and what can one catch that the other cannot?

level: middleimportance: must knowfreq 38%

basics

~20 s

timeout(200) polls and returns as soon as the verification passes, so it is an upper bound. after(200) always waits the whole 200 ms and only then asserts, so it can catch extra or late calls that timeout would have already passed over.

open as a page

CI intermittently fails on assertions written as verify(handler, timeout(50)).handle(event), which always pass on a developer laptop. How do you diagnose that, and when would you replace the timed verification with a CountDownLatch or a polling library such as Awaitility?

level: seniorimportance: should knowfreq 35%

basics

~20 s

A 50 ms budget is a guess about machine speed; loaded CI with fewer cores and GC pauses blows through it. Because timeout returns on success, raising it to a couple of seconds costs nothing and removes the flake. Replace it with a latch or Awaitility when you need a real happens-before edge or must poll state rather than an interaction.

open as a page

A teammate writes verify(mailer, timeout(500).never()).send(any()) in a Mockito test to prove no email is sent. What happens when that test runs, and how should the assertion be written instead?

level: seniorimportance: should knowfreq 25%

basics

~10 s

It does not work as a check: Mockito refuses timeout() combined with never() and throws a friendly-reminder misuse exception. Use verify(mailer, after(500).never()).send(any()), which waits the whole window before concluding nothing was sent.

open as a page

Across a large suite, when is waiting inside a mock verification the right tool at all, versus a sign the production code should expose a seam that makes the test deterministic? How would you set that policy for a team?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Timed verification is legitimate where asynchrony is the behaviour under test — typically integration-level boundaries. In unit tests it usually means the class hides its executor. Policy: inject execution seams, ban sleeps, allow generous timeouts at boundaries, keep full-wait afters rare and budgeted.

open as a page