Dedicated test support for Namastack Outbox #475
rolandbeisel
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Testing application code that uses the outbox currently requires users to assemble their own combination of mocks, repository access, Awaitility, and real-time delays. This becomes especially cumbersome for retry and backoff scenarios, where tests may need to wait for the scheduler even though the behavior under test is deterministic.
Would a dedicated OSS test-support module be useful?
Proposed module
testImplementation("io.namastack:namastack-outbox-test")The module could cover two distinct testing levels.
1. Verify scheduling in unit tests
A small
RecordingOutboxcould implement the publicOutboxAPI and record calls made by user code:This would only verify that application code invokes
Outbox.schedule(...)with the expected payload, key, and context. It would not test persistence, transaction boundaries, serialization, handler resolution, retries, or record processing. MockK and Mockito can already cover this use case, so the value ofRecordingOutboxwould mainly be a small, framework-independent convenience.2. Control the real runtime in Spring Boot integration tests
Following Spring Boot conventions, an
OutboxTestercould be enabled explicitly on an existing application test:Possible operations include:
The tester should use the actual configured persistence adapter and processing pipeline. It should expose immutable record snapshots rather than persistence-specific entities.
Time and processing
A mutable test
Clockalone is insufficient because advancing it does not trigger Spring's scheduler. Deterministic integration tests therefore need two capabilities:The first version can support this without replacing the existing processing architecture.
OutboxProcessingScheduler.process()already executes one complete polling cycle and waits for its batch to finish. An additive API could keep that method unchanged and expose a result-returning variant for test and operational use:OutboxTester.processOnce()would delegate toprocessNow(). The existing scheduled entry point, constructor, and default behavior would remain unchanged.Background polling still needs to be disabled while the tester controls processing. This could be provided through an opt-in property such as:
The default would remain
true. When disabled, the scheduler lifecycle could still enter a state that permits explicitprocessNow()calls, but it would not register a periodic task. An alternative that requires no production property is for the test auto-configuration to provide a manualTaskSchedulerthat records scheduled tasks without executing them. The explicit property is likely easier to understand and also useful outside this test module.Extracting a dedicated
OutboxProcessingCyclemay still improve the internal design later. It is not required for the initial test-support module and should only be done while preserving the existing publicOutboxProcessingSchedulerconstructor andprocess(): Unitmethod.Compatibility
The proposal can be implemented as a non-breaking addition:
namastack-outbox-testis a new optional test-scoped artifact;OutboxTester,RecordingOutbox, record snapshots, and test auto-configuration are new types;process(): Unit;Outboxor repository interfaces;Changing the return type of
OutboxProcessingScheduler.process(), replacing its public constructor, or adding a property to the primary constructor of a public Kotlin configuration data class could break compiled clients and should be avoided. If a processing-cycle abstraction is introduced, the old constructor and method signatures should delegate to the new implementation.Initial scope
An initial version could include:
OutboxTesterand@AutoConfigureOutboxTester;RecordingOutboxfor plain unit tests.It would intentionally avoid database-container management, persistence-specific assertions, a complete in-memory outbox implementation, and dependencies on a particular assertion or mocking library.
Open questions
schedule(...)calls already a significant use case?RecordingOutboxbe part of the first version, given that mocking libraries already support the same interaction tests?OutboxTesterthe right Spring Boot-style name?polling.enabledproperty, or should the test auto-configuration install a manual scheduler?processOnce()while the test thread still has an active transaction, since production processing happens after commit?Decision Process
All reactions