-
Notifications
You must be signed in to change notification settings - Fork 173
Description
Working with application modules, and ones driven by @ApplicationEventListener
s in particular introduces a couple of challenges:
- Events stimulating the module need to be published in a transactional way. Thus, the test code is likely to require access to
TransactionOperations
andApplicationEventPublisher
. - As these events are usually handled asynchronously, an Awaitility pipeline will have to be set up.
- Success or failure of an operation is usually determined by another event being published or some state change on the module being observed.
- Additional verifications on the resulting event, the observed state changed, or stimulus result need to be performed
While all of this can be assembled using already existing abstractions, it would be nice if there was a way to formulate such scenarios in a readable API. An event-based scenario could look something like this:
scenario.publish(new ProductAdded(productId)) // <1>
.andWaitAtMost(Duration.ofSeconds(2)) // <2>
.forEventOfType(InventoryItemAdded.class) // <3>
.toArriveAndVerify(it -> { // <4>
assertThat(inventory.findByProductIdentifier(productId)).isPresent();
assertThat(inventory.findById(it.id())).isPresent();
});
<1> Stimulates the system through an event publication.
<2> (Optional) Customizations of the execution
<3> Define expectation by describing the event that's supposed to appear, optionally defining filters.
<4> (Optional) Formulate additional verifications. The most simple variant is toArrive()
.
Alternatively, the scenario could be described based on state changes.
scenario.stimulate(tx -> …) // <1>
.forStateChange(() -> inventory.findByProductIdentifier(productId)) // <2>
.andVerify(it -> { // <3>
assertThat(it).…;
});
<1> Would trigger some method of a module's service or the like. Access TransactionOperations
to make sure that transactional event listeners are triggered for events potentially published during the operation.
<2> Inspect some state on the module. By default, accept a non-null (non-empty in the case of an Optional
) as concluding.
<3> Additional verifications based on the value returned by the stimulus or expected changed state (out of <2>).