diff --git a/spring-webflow-reference/src/testing.xml b/spring-webflow-reference/src/testing.xml
index cc3f015a..b1c325ce 100644
--- a/spring-webflow-reference/src/testing.xml
+++ b/spring-webflow-reference/src/testing.xml
@@ -8,15 +8,20 @@
+ Extending AbstractXmlFlowExecutionTests
To test the execution of a XML-based flow definition, extend AbstractXmlFlowExecutionTests:
public class BookingFlowExecutionTests extends AbstractXmlFlowExecutionTests {
+
}
+
+
+ Specifying the path to the flow to test
- At a minimum, you must override getResource(FlowDefinitionResourceFactory) to return the path to your flow:
+ At a minimum, you must override getResource(FlowDefinitionResourceFactory) to return the path to the flow you wish to test:
@Override
@@ -24,8 +29,12 @@ protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resou
return resourceFactory.createFileResource("src/main/webapp/WEB-INF/flows/booking/booking.xml");
}
+
+
+ Registering flow dependencies
- If your flow has dependencies on externally managed services, also override configureFlowBuilderContext(MockFlowBuilderContext) to register stubs or mocks of those services:
+ If your flow has dependencies on externally managed services,
+ also override configureFlowBuilderContext(MockFlowBuilderContext) to register stubs or mocks of those services:
@Override
@@ -33,12 +42,16 @@ protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext
builderContext.registerBean("bookingService", new StubBookingService());
}
+
+
+ Testing flow startup
Have your first test exercise the startup of your flow:
public void testStartBookingFlow() {
- Booking booking = createTestBooking();
+
+ Booking booking = createTestBooking();
MutableAttributeMap input = new LocalAttributeMap();
input.put("hotelId", "1");
@@ -53,14 +66,19 @@ public void testStartBookingFlow() {
Assertions generally verify the flow is in the correct state you expect.
+
+
+ Testing flow event handling
- Define additional tests to exercise event handling behavior.
+ Define additional tests to exercise flow event handling behavior.
You goal should be to exercise all paths through the flow.
You can use the convenient setCurrentState(String) method to jump to the flow state where you wish to begin your test.
public void testEnterBookingDetails_Proceed() {
+
setCurrentState("enterBookingDetails");
+
getFlowScope().put("booking", createTestBooking());
MockExternalContext context = new MockExternalContext();
@@ -68,6 +86,47 @@ public void testEnterBookingDetails_Proceed() {
resumeFlow(context);
assertCurrentStateEquals("reviewBooking");
+}
+
+
+
+ Mocking a subflow
+
+ To test calling a subflow, register a mock implementation of the subflow that asserts input was passed in correctly and
+ returns the correct outcome for your test scenario.
+
+
+public void testBookHotel() {
+
+ setCurrentState("reviewHotel");
+
+ Hotel hotel = new Hotel();
+ hotel.setId(1L);
+ hotel.setName("Jameson Inn");
+ getFlowScope().put("hotel", hotel);
+
+ getFlowDefinitionRegistry().registerFlowDefinition(createMockBookingSubflow());
+
+ MockExternalContext context = new MockExternalContext();
+ context.setEventId("book");
+ resumeFlow(context);
+
+ // verify flow ends on 'bookingConfirmed'
+ assertFlowExecutionEnded();
+ assertFlowExecutionOutcomeEquals("finish");
+}
+
+public Flow createMockBookingSubflow() {
+ Flow mockBookingFlow = new Flow("booking");
+ mockBookingFlow.setInputMapper(new Mapper() {
+ public MappingResults map(Object source, Object target) {
+ // assert that 1L was passed in as input
+ assertEquals(1L, ((AttributeMap) source).get("hotelId"));
+ return null;
+ }
+ });
+ // immediately return the bookingConfirmed outcome so the caller can respond
+ new EndState(mockBookingFlow, "bookingConfirmed");
}