Search code examples
javaunit-testingexceptionspring-webflow

Testing Spring Web Flow exception event


I have the following setup in my flow XML (my-flow.xml):

<view-state id="exceptionViewState" view="general_error" model="oneObjet"/>
...
<view-state id="previousViewState" view="previous_view" model="oneObjet">
    <transition on="actionConfirmed" to="endState" />
</view-state>
...
<global-transitions>
    <transition on-exception="com.xxx.exception.GeneralException" to="exceptionViewState"/>
</global-transitions>

And I am trying to test this flow XML by extending AbstractXmlFlowExecutionTests

public void testMyFlow_Exception() {
    setCurrentState("previousViewState");

    MockExternalContext context = new MockExternalContext();
    context.setEventId("com.xxx.exception.GeneralException");
    resumeFlow(context);

    assertCurrentStateEquals("exceptionViewState");
    assertResponseWrittenEquals("general_error", context);
}

When I run this test I get the following error:

org.springframework.webflow.engine.NoMatchingTransitionException: No transition found on occurence of event 'com.xxx.exception.GeneralException' in state 'previousViewState' of flow 'my-flow' -- valid transitional criteria are array<TransitionCriteria>[actionConfirmed] -- likely programmer error, check the set of TransitionCriteria for this state

At first glance it seems that the issue caused by using MockExternalContext#setEventId() method (which I think doesn't apply to exceptions) to try and emulate an exception being thrown. But I couldn't think of another way to do this. Any ideas on how this can be achieved?


Solution

  • I found a way around this by stubbing a service called in the web flow to throw the exception GeneralException. This allowed me to test the exception flow:

    public class ExceptionFlowTest extends AbstractXmlFlowExecutionTests {
    
        private MyService myService;
    
        protected void setUp() {
            myService = new MyService() {
    
                public ObjectDTO getObject() throws GeneralException {
                    throw new GeneralException();
                }
    
            };
        }
    
        @Override
        protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) {
            return resourceFactory.createFileResource("WebContent/WEB-INF/flows/my-flow.xml");
        }
    
        @Override
        protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
            builderContext.registerBean("myService", myService);
        }
    
        public void testMyFlow_Exception() {
    
            MutableAttributeMap input = new LocalAttributeMap();
            MockExternalContext context = new MockExternalContext();
    
            startFlow(input, context);
    
            assertCurrentStateEquals("exceptionViewState");
        }
    
    }
    

    I didn't have to change my flow XML :

    <flow xmlns="http://www.springframework.org/schema/webflow"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/webflow
                              http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
          start-state="getObject">
    
        <persistence-context />  
    
        <var name="object" class="com.xxx.model.ObjectDTO" />
    
         <action-state id="getObject">
            <evaluate expression="myService.getObject()" result="object" />
            <transition to="nextView" />
         </action-state>
    ...
        <global-transitions>
            <transition on-exception="com.xxx.exception.GeneralException" to="exceptionViewState"/>
        </global-transitions>
    
    </flow>