0

I'm kind of new to Spring Web Flow, My application uses Spring web flow version 2.0 and I've just started trying to implement some unit testing into my application(had no previous unit testing). This is my simple flow.

<?xml version="1.0" encoding="UTF-8"?>
<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"
    abstract="false" start-state="isDynamicMenu" >

    <action-state id="isDynamicMenu">
        <evaluate expression="menuMakerTestAction.isDynamicMenu" result="res"/>
        <transition on="yes" to="setDynamicMenu"/>
        <transition on="no" to="setCommonMenu"/>    
    </action-state>

    <view-state id="setDynamicMenu" />
    <view-state id="setCommonMenu" />

</flow>

and this is the test code:

public class FlowTest1 extends AbstractXmlFlowExecutionTests {

    private MenuMakerTestAction menuMakerTestAction;

    protected void setUp() {
        menuMakerTestAction = mock(MenuMakerTestAction.class);  
    }

    @Override
    protected FlowDefinitionResource getResource(
            FlowDefinitionResourceFactory resourceFactory) {        
        FlowDefinitionResource resource = resourceFactory
                .createResource("classpath:spring-webflow/config/menuMakerTest.xml");
        Assert.notNull(resource);
        return resource;
    }

    @Override
    protected void configureFlowBuilderContext(
            MockFlowBuilderContext builderContext) {
        builderContext.registerBean("menuMakerTestAction", menuMakerTestAction);        
    }

    @Test
    public void testFlow() throws GlobalException {
        MutableAttributeMap attrMap = new LocalAttributeMap();
        attrMap.put("res", "no");

        MockExternalContext context = new MockExternalContext();

        startFlow(attrMap, context);        
        assertCurrentStateEquals("setCommonMenu");        
    }
}

And this is the error I am getting:

org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@12f1bf0 targetAction = [EvaluateAction@1797795 expression = menuMakerTestAction.isDynamicMenu, resultExposer = [ActionResultExposer@19a0203 result = res, resultType = [null]]], attributes = map[[empty]]] in state 'isDynamicMenu' of flow 'menuMakerTest' -- action execution attributes were 'map[[empty]]' at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:60) at org.springframework.webflow.engine.ActionState.doEnter(ActionState.java:101) at org.springframework.webflow.engine.State.enter(State.java:194) at org.springframework.webflow.engine.Flow.start(Flow.java:535) at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:350) at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:221) at org.springframework.webflow.test.execution.AbstractFlowExecutionTests.startFlow(AbstractFlowExecutionTests.java:123) at ivr.latam.icg.view.menu.FlowTest1.testFlow(FlowTest1.java:71) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at junit.framework.TestCase.runTest(TestCase.java:176) at junit.framework.TestCase.runBare(TestCase.java:141) at junit.framework.TestResult$1.protect(TestResult.java:122) at junit.framework.TestResult.runProtected(TestResult.java:142) at junit.framework.TestResult.run(TestResult.java:125) at junit.framework.TestCase.run(TestCase.java:129) at junit.framework.TestSuite.runTest(TestSuite.java:255) at junit.framework.TestSuite.run(TestSuite.java:250) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Caused by: org.springframework.binding.expression.PropertyNotFoundException: Property 'menuMakerTestAction.isDynamicMenu' not found on context of class [org.springframework.webflow.engine.impl.RequestControlContextImpl] at org.springframework.binding.expression.ognl.OgnlExpression.getValue(OgnlExpression.java:87) at org.springframework.webflow.action.EvaluateAction.doExecute(EvaluateAction.java:77) at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188) at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145) at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51) ... 26 more

Caused by: ognl.NoSuchPropertyException: com.view.action.config.MenuMakerTestAction$$EnhancerByMockitoWithCGLIB$$9f5b5273.isDynamicMenu at ognl.ObjectPropertyAccessor.getProperty(ObjectPropertyAccessor.java:122) at ognl.OgnlRuntime.getProperty(OgnlRuntime.java:1657) at ognl.ASTProperty.getValueBody(ASTProperty.java:92) at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170) at ognl.SimpleNode.getValue(SimpleNode.java:210) at ognl.ASTChain.getValueBody(ASTChain.java:109) at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170) at ognl.SimpleNode.getValue(SimpleNode.java:210) at ognl.Ognl.getValue(Ognl.java:333) at org.springframework.binding.expression.ognl.OgnlExpression.getValue(OgnlExpression.java:85) ... 30 more

Its my first time posting in a forum. I can't get past this. The method isDynamicMenu receives nothing at all, and returns just a string. Any help would really be appreciated. Thanks!

SteveFerg
  • 3,466
  • 7
  • 19
  • 31

1 Answers1

0

SWF will not implicitly find Your "menuMakerTestAction" bean or any Spring bean registered to the application context. However, SWF will automatically register service classes (annotated with @Service,@Component) inside of SWF. (note: you can also call static methods from SWF)

So you must either:

A. explicitly initialize the menuMakerTestAction inside the flow definition

B. use a service method/static call to lookup the menuMakerTestAction bean

  1. so if you have a service called myService then you can use myService.getMyMenuMakerTestAction() inside the evaluate expression in the flow.

or

  1. Call a static method like such Printing log from flow.xml

also make sure:

"isDynamicMenu" is actually the attribute name on the class (and not the 'get' method name)

Community
  • 1
  • 1
Selwyn
  • 3,118
  • 1
  • 26
  • 33
  • Hi @Airduster, thanks for the response. I am pasting here the code of MenuMakerTestAction bean as well. public class MenuMakerTestAction { public String isDynamicMenu(){ return "no"; } }. Its not a attribute, just a method thats all. How do I initialize the menuMakerTestAction inside the flow definition. I dont want to change the classes thats already written and working fine in production. I just want to adapt the JUnit tests for the written classes. Thanks again for your help!! – Karlos Ramirez Jul 30 '15 at 18:25
  • @Karlos Ramirez That is your problem. You need to be using standard getters/settors for your beans. Webflow needs to be able to resolve "MenuMakerTestAction.isDynamicMenu" via reflection.... So it's going to look for a public String getIsDynamicMenu() { return isDynamicMenu;} method on that MenuMakerTestAction class. so the "isDynamicMenu" in the – Selwyn Jul 30 '15 at 18:29
  • Hi @Airduster, Thanks for helping me. So I did made it work by changing from simple method to property with getter and setter and the test works fine! So is there a way to call a method simply? The thing is, the classes that are in production are like this only : a method that returns a Event. The method is not declared with a property. So is there any way to test those methods? or do I have to declare a class for each test/flow on my own and return mock values to test the flow? Hope I explain myself. Thanks again a lot for your invaluable time and help!! – Karlos Ramirez Jul 31 '15 at 16:09
  • sorry all along the error was different.The error is org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@f8395f targetAction = Mock for MenuMakerAction, hashCode: 2281830, attributes = map['method' -> 'isDynamicMenu']] in state 'isDynamicMenu' of flow 'menuMakerTest' -- action execution attributes were 'map[[empty]]' Caused by: java.lang.NullPointerException at org.springframework.webflow.action.MultiAction.doExecute(MultiAction.java:122) at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188) – Karlos Ramirez Jul 31 '15 at 18:29
  • Could you tell me why its causing the null pointer exception error? – Karlos Ramirez Jul 31 '15 at 18:35
  • Attaching the complete log: – Karlos Ramirez Jul 31 '15 at 18:59
  • DEBUG FlowExecutionImplFactory:78 - Creating new execution of 'menuMakerTest' DEBUG FlowExecutionImpl:213 - Starting in org.springframework.webflow.test.MockExternalContext@14a75bb with input map['isDynamicMenu' -> 'isDynamicMenu'] DEBUG ActionState:189 - Entering state 'isDynamicMenu' of flow 'menuMakerTest' DEBUG ActionExecutor:49 - Executing [EvaluateAction@39c8c1 expression = menuMakerAction.isDynamicMenu, resultExposer = [null]] DEBUG AnnotatedAction:142 - Putting action execution attributes map[[empty]] – Karlos Ramirez Jul 31 '15 at 19:54
  • DEBUG DefaultListableBeanFactory:214 - Returning cached instance of singleton bean 'menuMakerAction' DEBUG ActionExecutor:49 - Executing Mock for MenuMakerAction, hashCode: 10140210 DEBUG AnnotatedAction:142 - Putting action execution attributes map['method' -> 'isDynamicMenu'] DEBUG AnnotatedAction:149 - Clearing action execution attributes map['method' -> 'isDynamicMenu'] DEBUG AnnotatedAction:149 - Clearing action execution attributes map[[empty]] – Karlos Ramirez Jul 31 '15 at 19:55
  • DEBUG FlowExecutionImpl:587 - Attempting to handle [org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@d67067 targetAction = Mock for MenuMakerAction, hashCode: 10140210, attributes = map['method' -> 'isDynamicMenu']] in state 'isDynamicMenu' of flow 'menuMakerTest' -- action execution attributes were 'map[[empty]]'] with root cause [java.lang.NullPointerException] DEBUG FlowExecutionImpl:604 - Rethrowing unhandled flow execution exception. – Karlos Ramirez Jul 31 '15 at 19:55
  • cannot tell from the stacktrace what is causing the NullPointerException but... 99% of time it is developer error. I really think you are suffering from bad design. You need to decide here what your domain objects are and what you service classes are (which will retrieve the domain objects) and SEPARATE the concerns.. Sounds like MenuMakerAction is a domain object so maybe adding a MenuMakerService class with a '@'Service annotation. The '@'Service annotation would allow you to directly call methods on the service class in webflow like menuMarkerService.getMyMenuMakerAction(). – Selwyn Jul 31 '15 at 21:18