SagaSpec

abstract class SagaSpec<T : Any>(block: StatelessSagaDsl<T>.() -> Unit) : AbstractDynamicTestBuilder

Abstract base class for writing stateless saga specification tests using JUnit 5.

This class provides a DSL-based framework for testing stateless sagas by defining scenarios with events and expected command outcomes. It uses JUnit 5's @TestFactory to generate dynamic tests from the specification.

The primary purpose is to facilitate behavior-driven testing of sagas, allowing developers to specify expected command emissions in response to domain events. It enables testing saga logic in isolation without requiring full infrastructure setup.

Example usage:

class CartSagaSpec : SagaSpec<CartSaga>({
on {
val ownerId = generateGlobalId()
val orderItem = OrderItem(
id = generateGlobalId(),
productId = generateGlobalId(),
price = BigDecimal.valueOf(10),
quantity = 10,
)
whenEvent(
event = mockk<OrderCreated> {
every { items } returns listOf(orderItem)
every { fromCart } returns true
},
ownerId = ownerId
) {
expectCommandType(RemoveCartItem::class)
expectCommand<RemoveCartItem> {
aggregateId.id.assert().isEqualTo(ownerId)
body.productIds.assert().hasSize(1)
body.productIds.assert().first().isEqualTo(orderItem.productId)
}
}
}
})

Parameters

T

The type of the saga being tested, must be a class that implements the saga logic.

Constructors

Link copied to clipboard
constructor(block: StatelessSagaDsl<T>.() -> Unit)

Properties

Link copied to clipboard
open override val dynamicNodes: MutableList<DynamicNode>

A mutable list of dynamic test nodes that can be modified by subclasses.

Link copied to clipboard

The processor type of the saga being tested, extracted from the generic type parameter.

Functions

Link copied to clipboard
@TestFactory
fun execute(): Stream<DynamicNode>

Executes the saga test specification and returns a stream of dynamic test nodes.