The problem
Currently, Quarkus Flow provides the WorkflowExecutionListener interface for listening to workflow lifecycle events in production code. However, there's no dedicated test framework or module that allows developers to easily assert on these events during integration tests or unit tests.
Developers testing workflows today can only assert on the final workflow result, but cannot easily verify:
- The sequence of events that occurred during execution
- Specific task completions and their outputs
- Workflow state transitions
- Event timing and ordering
- Intermediate workflow states
Current Testing Approach
Current tests follow this pattern:
@QuarkusTest
class HelloWorkflowTest {
@Inject
HelloWorkflow workflow;
@Test
void should_produce_hello_message() throws Exception {
WorkflowModel result = workflow.instance(Map.of())
.start()
.toCompletableFuture()
.get(5, TimeUnit.SECONDS);
// Can only assert on final result
assertThat(result.asMap().orElseThrow().get("message"), is("hello world!"));
}
}
Proposed solution / API
Proposed Solution
Create a quarkus-flow-testing module that provides:
1. Test Listener/Recorder
A test-scoped listener that records all workflow events during test execution:
@QuarkusTest
class WorkflowEventTest {
@Inject
WorkflowEventRecorder eventRecorder; // New test utility
@Inject
MyWorkflow workflow;
@Test
void should_complete_all_tasks_in_order() {
eventRecorder.startRecording(); // or auto-start per test
workflow.instance(Map.of()).start().await().indefinitely();
// Assert on recorded events
eventRecorder.assertThat()
.workflowStarted()
.taskStarted("task1")
.taskCompleted("task1")
.taskStarted("task2")
.taskCompleted("task2")
.workflowCompleted();
}
}
2. Fluent Assertion API
Provide a fluent API for asserting on workflow events:
// Assert on event sequence
eventRecorder.assertThat()
.hasWorkflowStartedEvent()
.hasTaskCompletedEvent("inc")
.withOutput(output -> {
assertThat(output.asMap().get("count")).isEqualTo(1);
});
// Assert on event count
eventRecorder.assertThat()
.hasTaskStartedEventCount(3)
.hasTaskCompletedEventCount(3);
// Assert on event timing
eventRecorder.assertThat()
.taskCompletedBefore("task1", "task2")
.workflowCompletedWithin(Duration.ofSeconds(5));
// Assert on specific event properties
eventRecorder.assertThat()
.hasTaskFailedEvent("risky-task")
.withError(error -> {
assertThat(error.getMessage()).contains("Connection timeout");
});
3. Event Matchers
Provide Hamcrest-style matchers for more flexible assertions:
assertThat(eventRecorder.getEvents(),
hasEvent(workflowStarted(withWorkflowId("my-workflow"))));
assertThat(eventRecorder.getEvents(),
hasEvent(taskCompleted("inc", withOutput(containsEntry("count", 1)))));
4. Conditional Waiting
Support waiting for specific events during async workflow execution:
@Test
void should_suspend_and_resume() {
workflow.instance(Map.of()).start();
// Wait for specific event before proceeding
eventRecorder.waitFor()
.workflowSuspended()
.timeout(Duration.ofSeconds(5));
// Resume workflow
workflowService.resume(instanceId);
eventRecorder.waitFor()
.workflowResumed()
.workflowCompleted();
}
5. Event Filtering and Querying
Allow filtering and querying recorded events:
// Get all task events
List<TaskEvent> taskEvents = eventRecorder.getTaskEvents();
// Get events for specific workflow instance
List<WorkflowEvent> instanceEvents =
eventRecorder.getEventsForInstance(instanceId);
// Filter by event type
List<TaskCompletedEvent> completedTasks =
eventRecorder.getEvents(TaskCompletedEvent.class);
Implementation Considerations
Module Structure
quarkus-flow-testing/
├── runtime/
│ ├── WorkflowEventRecorder.java
│ ├── FluentEventAssertions.java
│ ├── EventMatchers.java
│ └── TestWorkflowExecutionListener.java
├── deployment/
│ └── TestingProcessor.java (auto-register test listener)
└── integration-tests/
└── (comprehensive test examples)
Key Features
- Automatic Registration: Test listener should be automatically registered in test scope
- Thread-Safe: Support concurrent test execution
- Test Isolation: Events should be isolated per test method
- JUnit Integration: Provide JUnit 5 extension for automatic setup/teardown
- AssertJ Integration: Leverage AssertJ for fluent assertions
- Quarkus Test Profile: Support different test profiles with different listener configurations
Example Test Scenarios
The framework should support testing:
- Sequential task execution
- Parallel task execution
- Workflow suspension/resumption
- Error handling and retries
- Compensation flows
- Event timing and performance
- State transitions
- Task output validation
Benefits
- Better Test Coverage: Verify not just the final result, but the entire execution path
- Easier Debugging: Recorded events provide insight into what happened during test failures
- Behavior Verification: Assert on workflow behavior, not just outcomes
- Integration Testing: Better support for testing complex workflow scenarios
- Documentation: Tests become living documentation of workflow behavior
Related Work
- Existing
WorkflowExecutionListener interface (production use)
- Current test patterns using
@QuarkusTest and @Inject
- Example listener:
examples/suspend-resume-abort/src/main/java/org/acme/flow/FlowCustomListener.java
Acceptance Criteria
Open Questions
- Should this be a separate module or part of the core testing utilities?
- Should we support both JUnit 4 and JUnit 5, or only JUnit 5?
- Should event recording be opt-in or automatic in test scope?
- How should we handle event recording in durable/persistent workflows?
- Should we provide integration with other testing frameworks (TestNG, Spock)?
References
Alternatives considered
No response
Area(s)
Impact & scope
No response
The problem
Currently, Quarkus Flow provides the
WorkflowExecutionListenerinterface for listening to workflow lifecycle events in production code. However, there's no dedicated test framework or module that allows developers to easily assert on these events during integration tests or unit tests.Developers testing workflows today can only assert on the final workflow result, but cannot easily verify:
Current Testing Approach
Current tests follow this pattern:
Proposed solution / API
Proposed Solution
Create a
quarkus-flow-testingmodule that provides:1. Test Listener/Recorder
A test-scoped listener that records all workflow events during test execution:
2. Fluent Assertion API
Provide a fluent API for asserting on workflow events:
3. Event Matchers
Provide Hamcrest-style matchers for more flexible assertions:
4. Conditional Waiting
Support waiting for specific events during async workflow execution:
5. Event Filtering and Querying
Allow filtering and querying recorded events:
Implementation Considerations
Module Structure
Key Features
Example Test Scenarios
The framework should support testing:
Benefits
Related Work
WorkflowExecutionListenerinterface (production use)@QuarkusTestand@Injectexamples/suspend-resume-abort/src/main/java/org/acme/flow/FlowCustomListener.javaAcceptance Criteria
quarkus-flow-testingmodule createdWorkflowEventRecorderbean available in test scopeOpen Questions
References
Alternatives considered
No response
Area(s)
Impact & scope
No response