Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: How do I set a variable in flow scope in a unit test?

  1. #1
    Join Date
    Apr 2009
    Posts
    22

    Question How do I set a variable in flow scope in a unit test?

    Hi there.

    I've been facing this problem for a few days now and haven't been able to find a solution, not in the forums nor on the net or by playing around. I'm pretty sure that I'm just missing something trivial. But you know how it is...

    Anyway, the problem is the following part of my flow:
    Code:
    <view-state id="manager_welcome" view="/manager/manager_welcome">
            <on-entry>
                <evaluate expression="dataManager.getAppUser(currentUser)" result="flowScope.currentAppUser"/>
                <set name="flowScope.currentRole" value="currentAppUser.getAuthority()" />
            </on-entry>
    And this is the test for that part:
    Code:
    public void testStartManagerFlow() {            
            this.context.setCurrentUser(new PrincipalSpringSecurityUserToken(
                    "", "", "", new GrantedAuthority[]{new GrantedAuthorityImpl("user")}, 
                    "principal"));
            
            
            expect(this.dataManager.getAppUser((PrincipalSpringSecurityUserToken) this.context.getCurrentUser()))
                .andReturn(new User());
    
            replay(this.dataManager);
            startFlow(this.context);
            assertTrue(getRequiredFlowAttribute("dataManager") instanceof IDataManager);
            assertCurrentStateEquals("manager_welcome");
            
            verify(this.dataManager);
        }
    I have this method getAppUser(PrincipalSpringSecurityUserToken) that returns an object of type User. Now the test gives me an NPE because the variable currentAppUser is null. So far so good, I didn't set the variable so it has to be null.
    But how the heck do I set that variable? I'm really at loss here.

    Thanks for taking a glance

    theseion

  2. #2

    Default

    What kind of unit test are you using? What is the context?

  3. #3

    Default

    Nevermind, I guess you are using someting like AbstractXmlFlowExecutionTests. Well, the currentAppUser variable should be set by your flow:

    <evaluate expression="dataManager.getAppUser(currentUser)" result="flowScope.currentAppUser"/>

    so it is not a matter of setting the variable. Are you sure where exactly you are getting the NPE?

  4. #4
    Join Date
    Apr 2009
    Posts
    22

    Default

    I'm indeed using AbstractXmlFlowExecutionTest.

    the currentAppUser variable should be set by your flow
    That's exactly what I thought. But since the DataManager object is a Mock object getAppUser() will not return anything on it's own (is that correct?).
    My understanding is that I tell the flow what the method returns by using andReturn() on the expected() method call like this:

    expect(this.dataManager.getUser(<currentUser>)).an dReturn(new User());

    But if that understanding was wrong I would have to set that variable in a different way, as far as I can see...

    The NPE is defenitely thrown because the variable currentAppUser is null.

    Thanks for you help nkaza.

  5. #5

    Default

    Yes, that's correct. That's how you setup mock object behavior in EasyMock.

    Now, I assume you have this code somewhere:

    Code:
    	@Override
    	protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
    	    builderContext.registerBean("dataManager", this.dataManager);
    	}
    and this:

    Code:
    this.dataManager = createStrictMock(IDataManager.class);

    I am not sure if this line makes sense:

    Code:
    assertTrue(getRequiredFlowAttribute("dataManager") instanceof DataManager);

    Other than that it seems correct. There shouldn't be anything else you need to do. If you still have problems, post the entire TestCase code and flow.
    Nazaret Kazarian

  6. #6
    Join Date
    Apr 2009
    Posts
    22

    Default

    I do have those lines in my code. I really don't see the problem so I'll post the code.

    manager-flow:
    Code:
    <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">
    
        <secured attributes="ROLE_SUPER_MANAGER, ROLE_SECTION_MANAGER" match="any"/>
        
        <var name="dataManager" class="ch.unibe.iam.applicationManager.service.DataManager" />
        
        <!-- 
            view states
         -->
    
        <view-state id="manager_welcome" view="/manager/manager_welcome">
            <on-entry>
                <evaluate expression="dataManager.getUser(currentUser)" result="flowScope.currentAppUser"/>
                <set name="flowScope.currentRole" value="currentAppUser.getAuthority()" />
                <set name="flowScope.currentState" value="flowExecutionContext.activeSession.state.id" />
            </on-entry>
            <on-render>
                <evaluate expression="dataManager.getLatestDossiers(flowExecutionUrl, currentAppUser)" result="flowScope.latestDossiersByState"/>
            </on-render>
            <transition on="select_dossier_action" to="view_dossier">
                <evaluate expression="dataManager.getDossier(requestParameters.dossier)" result="flowScope.currentDossier"/>
            </transition>
        </view-state>
    
    ...
    test:
    Code:
    public class ManagerWelcomeTest extends AbstractXmlFlowExecutionTests{
    
        private IDataManager dataManager;
        private MockExternalContext context;
        
         protected void setUp() {
             this.context = new MockExternalContext();
             this.dataManager = createStrictMock(IDataManager.class);
         }
         
        @Override
        protected FlowDefinitionResource getResource(
                FlowDefinitionResourceFactory resourceFactory) {
            return resourceFactory.createFileResource(
                    "src/main/webapp/WEB-INF/flows/manager-flow.xml");
        }
        
        @Override
        protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
            builderContext.registerBean("dataManager", this.dataManager);
        }
    
        
        /*
         * Test cases
         */
        public void testStartManagerFlow() {
            User user = new User();
    	user.setAuthority(Role.USER.getRoleName());
    		
            PrincipalSpringSecurityUserToken authToken = new PrincipalSpringSecurityUserToken(
    		"key", "username", "password", new GrantedAuthority[]{
    		new GrantedAuthorityImpl(Role.USER.getRoleName())
    		}, user);
    		
            this.context.setCurrentUser(authToken);
    		
    	expect(this.dataManager.getUser(authToken)).andReturn(user);
    	replay(this.dataManager);
    		
    	startFlow(this.context);
    	assertCurrentStateEquals("manager_welcome");
    	verify(this.dataManager);
        }
    
    ...
    The line causing the exception is this one in the flow:
    Code:
    <set name="flowScope.currentRole" value="currentAppUser.getAuthority()" />
    and this line in the test:
    Code:
    startFlow(this.context);

    That should be all of the relevant code. Please let me know if you need to see more.
    Last edited by theseion; May 10th, 2009 at 02:31 PM.

  7. #7

    Default

    Ok just remove this line from the flow:

    Code:
    <var name="dataManager" class="ch.unibe.iam.applicationManager.service.DataManager" />
    The dataManager is registered in configureFlowBuilderContext. The var you have declared replaces it with a simple instance of DataManager.
    Nazaret Kazarian

  8. #8
    Join Date
    Apr 2009
    Posts
    22

    Default

    aaaah!
    That means though, that I'll have to have a "testable" version of my flows. Is that common practice?

    Again, thanks a lot for your help! Much appreciated.

  9. #9

    Default

    Not really. The proper way is to declare the dataManager as a spring bean, not as a var. So the test case is just providing a mock implementation of the spring bean.
    Nazaret Kazarian

  10. #10
    Join Date
    Apr 2009
    Posts
    22

    Default

    Well, I'd say there's definitely room for improvement on this matter. What's the use of such a construct if you can't have it in you test...

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •