Class TestOutboxRecordCaptor
OutboxRecord written during a
test. Replaces the JPA-backed repository in test scope so consumers can
assert against emitted events without standing up Postgres.
Assertion methods follow AssertJ-style naming and produce diagnostic
messages including the observed status distribution so failures point
directly at the divergence (e.g. "Expected exactly 1 PENDING record
but found 2; statuses observed: [PENDING x1, SENT x1]").
Status-at-capture semantics (R2 fix): assertions use the
status that the row carried at capture(OutboxRecord) time, NOT
the live status of the underlying OutboxRecord reference. The
in-memory repository mutates rows in-place during
markSent / markFailureAttempt, so a captor that reads
record.getStatus() at assertion time would observe SENT/FAILED
for rows captured AT save time as PENDING — spuriously failing
assertEmittedExactly(N, PENDING) after a full publish cycle.
The captor stores a snapshot of the status alongside the reference;
listEmitted() still returns the live references for callers
that want post-mutation introspection.
Thread-safety: the captor uses an internal
ConcurrentLinkedQueue, so concurrent calls to capture(OutboxRecord)
from multiple writer threads are safe. Tests that assert ordering across
concurrent producers MUST still pin a single executor to avoid scheduler
non-determinism in the visible sequence.
Wired by OutboxTestAutoConfiguration when AutoConfigureOutbox
is present on a test class.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidassertEmittedExactly(int expectedCount, OutboxRecord.Status expectedStatus) Asserts that exactlyexpectedCountrecords were emitted withexpectedStatusat capture time.voidAsserts that the captor recorded zero emissions.voidclear()Clears all captured records.Returns every record captured during the test, in insertion order.
-
Constructor Details
-
TestOutboxRecordCaptor
public TestOutboxRecordCaptor()
-
-
Method Details
-
listEmitted
Returns every record captured during the test, in insertion order. The returned references are the LIVE records — callers that need post-mutation introspection (e.g. asserting the in-memory repo flipped a row to SENT) read from here. For status assertions against the insertion-time state, useassertEmittedExactly(int, OutboxRecord.Status)which uses the snapshot status (R2 fix).- Returns:
- immutable list snapshot; non-null
-
assertEmittedExactly
Asserts that exactlyexpectedCountrecords were emitted withexpectedStatusat capture time. ThrowsAssertionErrorwith a diagnostic message listing the observed status distribution (also at capture time) when the assertion fails.- Parameters:
expectedCount- required number of matching recordsexpectedStatus- required status for each matched record; non-null- Throws:
AssertionError- when the captor did not record exactlyexpectedCountentries withexpectedStatusat capture time
-
assertNoEmissions
public void assertNoEmissions()Asserts that the captor recorded zero emissions. Common after negative-path tests (e.g., transaction rolled back; nothing was supposed to land in the outbox).- Throws:
AssertionError- when the captor recorded one or more emissions
-
clear
public void clear()Clears all captured records. Convenience for tests that share a Spring context across methods (rare; isolated contexts are preferred).
-