diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java index de22d803..60a4a007 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java @@ -18,6 +18,7 @@ import org.springframework.util.ClassUtils; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceView; import org.springframework.web.servlet.view.JstlView; +import org.springframework.webflow.action.ViewFactoryActionAdapter; import org.springframework.webflow.core.collection.ParameterMap; import org.springframework.webflow.engine.builder.ViewFactoryCreator; import org.springframework.webflow.execution.Action; @@ -239,21 +240,4 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon } - /** - * Simple adapter that adapts a view factory render cycle to the action interface. - * @author Keith Donald - */ - private static class ViewFactoryActionAdapter implements Action { - private ViewFactory viewFactory; - - public ViewFactoryActionAdapter(ViewFactory viewFactory) { - this.viewFactory = viewFactory; - } - - public Event execute(RequestContext context) throws Exception { - viewFactory.getView(context).render(); - return new Event(this, "success"); - } - } - } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java b/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java index 36618d68..7153d3db 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/FlowBuilderSystemDefaults.java @@ -15,28 +15,30 @@ class FlowBuilderSystemDefaults { defaultServices = new FlowBuilderServices(); defaultServices.setFlowArtifactFactory(new FlowArtifactFactory()); defaultServices.setBeanInvokingActionFactory(new BeanInvokingActionFactory()); + defaultServices.setViewFactoryCreator(new MockViewFactoryCreator()); defaultServices.setConversionService(new DefaultConversionService()); defaultServices.setExpressionParser(DefaultExpressionParserFactory.getExpressionParser()); defaultServices.setResourceLoader(new DefaultResourceLoader()); defaultServices.setBeanFactory(new StaticListableBeanFactory()); } + public static FlowBuilderServices get() { + return new FlowBuilderSystemDefaults().createBuilderServices(); + } + public FlowBuilderServices createBuilderServices() { FlowBuilderServices builderServices = new FlowBuilderServices(); applyDefaults(builderServices); return builderServices; } - public void applyDefaults(FlowBuilderServices services) { + private void applyDefaults(FlowBuilderServices services) { services.setFlowArtifactFactory(defaultServices.getFlowArtifactFactory()); services.setBeanInvokingActionFactory(defaultServices.getBeanInvokingActionFactory()); + services.setViewFactoryCreator(defaultServices.getViewFactoryCreator()); services.setConversionService(defaultServices.getConversionService()); services.setExpressionParser(defaultServices.getExpressionParser()); services.setResourceLoader(defaultServices.getResourceLoader()); services.setBeanFactory(defaultServices.getBeanFactory()); } - - public static FlowBuilderServices get() { - return new FlowBuilderSystemDefaults().createBuilderServices(); - } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java index 2dbcef39..bff880dc 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractExternalizedFlowExecutionTests.java @@ -17,6 +17,7 @@ package org.springframework.webflow.test.execution; import org.springframework.core.io.Resource; import org.springframework.webflow.config.FlowDefinitionResource; +import org.springframework.webflow.config.FlowDefinitionResourceFactory; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.engine.Flow; @@ -47,6 +48,11 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo */ private boolean cacheFlowDefinition = false; + /** + * A helper for constructing paths to flow definition resources in the filesystem, classpath, or other location. + */ + private FlowDefinitionResourceFactory resourceFactory = new FlowDefinitionResourceFactory(); + /** * Constructs a default externalized flow execution test. * @see #setName(String) @@ -137,7 +143,7 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo * @return the built flow definition, ready for execution */ protected final Flow buildFlow() { - FlowDefinitionResource resource = getFlowDefinitionResource(); + FlowDefinitionResource resource = getResource(resourceFactory); FlowBuilderContext builderContext = createFlowBuilderContext(resource); FlowBuilder builder = createFlowBuilder(resource.getPath()); FlowAssembler assembler = new FlowAssembler(builder, builderContext); @@ -166,9 +172,10 @@ public abstract class AbstractExternalizedFlowExecutionTests extends AbstractFlo /** * Get the flow definition to be tested. + * @param a helper for constructing the resource to be tested * @return the flow definition resource */ - protected abstract FlowDefinitionResource getFlowDefinitionResource(); + protected abstract FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory); /** * Create the flow builder to build the flow at the specified resource location. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java index 802a2fe9..93b9ccf7 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/test/execution/AbstractFlowExecutionTests.java @@ -24,6 +24,8 @@ import org.springframework.webflow.engine.impl.FlowExecutionImplFactory; import org.springframework.webflow.execution.FlowExecution; import org.springframework.webflow.execution.FlowExecutionException; import org.springframework.webflow.execution.FlowExecutionFactory; +import org.springframework.webflow.test.MockExternalContext; +import org.springframework.webflow.test.MockParameterMap; /** * Base class for integration tests that verify a flow executes as expected. Flow execution tests captured by subclasses @@ -117,6 +119,45 @@ public abstract class AbstractFlowExecutionTests extends TestCase { flowExecution.resume(context); } + /** + * Signal the event against the paused flow execution. The event id will be translated into a Event object by the + * configured view factory and raised as an Event against the current view state. The event will cause the flow to + * change states if it matches a transition. + * @param eventId the event identifier + */ + protected void signalEvent(String eventId) { + MockExternalContext context = new MockExternalContext(); + context.putRequestParameter("_eventId", eventId); + resumeFlow(context); + } + + /** + * Signal the event against the paused flow execution. The event id will be translated into a Event object by the + * configured view factory and raised as an Event against the current view state. The event will cause the flow to + * change states if it matches a transition. + * @param eventId the event identifier + * @param input event input parameters + */ + protected void signalEvent(String eventId, MockParameterMap input) { + MockExternalContext context = new MockExternalContext(input); + context.putRequestParameter("_eventId", eventId); + resumeFlow(context); + } + + /** + * Signal the event against the paused flow execution. The event id will be translated into a Event object by the + * configured view factory and raised as an Event against the current view state. The event will cause the flow to + * change states if it matches a transition. + * @param eventId the event identifier + * @param parameterName the name of the parameter + * @param parameterValue the value of the parameter + */ + protected void signalEvent(String eventId, String parameterName, String parameterValue) { + MockParameterMap input = new MockParameterMap(); + input.put(parameterName, parameterValue); + signalEvent(eventId, input); + } + // convenience accessors /** diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java b/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java index 766b61d6..95399777 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java @@ -22,6 +22,7 @@ import org.springframework.binding.mapping.AttributeMapper; import org.springframework.binding.mapping.MappingContext; import org.springframework.webflow.config.FlowDefinitionResource; import org.springframework.webflow.config.FlowDefinitionResourceFactory; +import org.springframework.webflow.context.ExternalContext; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.engine.EndState; import org.springframework.webflow.engine.Flow; @@ -32,21 +33,34 @@ import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests; */ public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests { - protected FlowDefinitionResource getFlowDefinitionResource() { - return new FlowDefinitionResourceFactory().createClassPathResource("search-flow.xml", getClass()); + protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) { + return resourceFactory.createClassPathResource("search-flow.xml", getClass()); } public void testStartFlow() { - // startFlow(new MockExternalContext()); + ExternalContext context = new MockExternalContext(); + startFlow(context); + assertCurrentStateEquals("enterCriteria"); } public void testCriteriaSubmitSuccess() { + startFlow(new MockExternalContext()); + signalEvent("search"); + assertCurrentStateEquals("displayResults"); } public void testNewSearch() { + startFlow(new MockExternalContext()); + signalEvent("search"); + signalEvent("newSearch"); + assertCurrentStateEquals("enterCriteria"); } public void testSelectValidResult() { + startFlow(new MockExternalContext()); + signalEvent("search"); + signalEvent("select", "id", "1"); + assertCurrentStateEquals("displayResults"); } protected void configure(MockFlowBuilderContext builderContext) { @@ -63,7 +77,7 @@ public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests { builderContext.registerBean("phonebook", new TestPhoneBook()); } - static class TestPhoneBook { + public static class TestPhoneBook { public List search(Object criteria) { ArrayList res = new ArrayList(); res.add(new Object()); diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml index 7cc96480..4bd5dd1c 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml @@ -2,7 +2,7 @@ + http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> @@ -19,7 +19,7 @@ - + @@ -31,7 +31,7 @@ - +