Vishwanath Krishnamurthi's blog

A blog on Java EE, clean code, open source and TDD

Archive for the ‘Spring’ Category

Spring Webflow – Tips

with one comment

Just a random list of tips – handy if you are using SWF

Passing a String in an evaluate expression:

To pass a string literal, enclose the string in single quotes ‘ ‘ as in


<evaluate expression="searchService.fetchSearchResult('hello')  result="flowScope.searchResult" />

Set a boolean 

Likewise to set a boolean value,

<set name="flowScope.isTicketAvailable" value=" 'true' "/>

Flush flow changes without restarting the server

While developing, do set, development=true as such and save yourself lots of time

<flow:flow-builder-services id="flowBuilderServices"
 view-factory-creator="viewFactoryCreator" development="true"/>


The RequestControlContext object

 On the rare cases where you need a requestControlContext in your bean, you can get hold of it by passing ‘flowRequestContext’ from the flow.

<evaluate expression="someBean.someMethod( flowRequestContext)">

public void someMethod(RequestControlContext context){ //your operation
}

The start state

During development, if you wanted to skip ahead a few states, just define the start-state in the <flow> element.

Want to trace the flow?

Its pretty simple to add a couple of methods in your listener that extends FlowExecutionListenerAdapter

@Override
 public void stateEntered(RequestContext context,
 StateDefinition previousState, StateDefinition newState) {
logger.debug("Entered State:" + newState.getId());
 }
  @Override
 public void transitionExecuting(RequestContext context, TransitionDefinition transition)
 {
 logger.debug("Executing transition:" + transition.getId());
 }

and trace the flow.

Written by Vishwanath Krishnamurthi

May 19, 2012 at 1:37 am

Posted in Spring

Tagged with , ,

Using mockito to unit test Spring Webflow (2)

with one comment

This is as a continuation to this post on unit testing flows in Spring Webflow.

I wish to start testing  from an intermediate state (other than start state )

Sure, No Problem.

@Test
public void  discountCheck()
{
this.setCurrentState("viewDiscountDetails");
resumeFlow(context);
//Now we should be in viewDiscountDetails state. Can fire any transition defined for this state.
context.setEventId("checkIfDiscountValid");
resumeFlow(context);
}

So the only thing to watch in the above snippet is that, if  you are starting your test from an intermediate state,  set the state to start with and then use resumeFlow()  instead of using startFlow() .

Also note that the <on-entry> …. </on-entry> expressions of  ‘viewDiscountsDetails’ state are not evaluated when the test is executed. I think that is because by setting the currentState, we have told SWF, that the state has already been entered. (So it wouldn’t bother with the on-entry expressions 😀 )

How about stubbing of some scoped attributes ?

We could simply add this line in the test.

this.getFlowScope().put("productSelected", new Car());

But note that this line is valid only after you’ve started a flow.. Hence the following would result in an error, since there’s no active flow.

this.getFlowScope().put("productSelected", new Car());
this.startFlow();

Asserting  for an action-state  doesn’t work

Once a flow is started, it goes through the decision-states or action-states and pauses its execution only in a view-state. Hence asserting a current state to be an action state or a decision state would never pass.

Instead, we can use  the verify method in mockito to test if a method in the action was indeed invoked.


   this.startFlow(context);
   context.setEventId("processPayment");
   resumeFlow(context);
   verify(mockedBazService.paymentProcess(accountInfo)); // verify an action method was executed
  assertCurrentStateEquals("paymentSuccessfulView"); //assert execution has paused in this view state

Switching to some general talk, the question we’d have while writing these unit tests is

What could SWF unit-testing expose ?

I haven’t tried with all the below points, but looks like it is all possible.

  • Ensure validators bound were actually called
  • Ensure exception handler catches exceptions as expected
  • Ensure a matching transition does exist 
  • Ensure the traversal path was as expected 
  • Ensure a model is bound to a view correctly : assertModelAttributeNotNull()
  • Help us in the use of right attributes in the right scope: getRequired<XXX>Attribute() asserts that an attribute is present in that scope. Ensure it is present / cleared etc. Probably the best way to understand the use of flashScope, viewScope etc that SWF provides. 
  • Ensure a view was resolved as expected
  • Simulate a refresh and run some asserts
I wish to trace the flow better / I would like to make some hacky workarounds:
Its pretty easy to attach a listener to the flow using
this.setFlowExecutionListener( new MyListener());
where MyListener is a class that extends FlowExecutionListenerAdapter and overrides the required methods.
Well then, I’ve typed enough.. Time I get back to my IDE. Enjoy your coding ! and do let me know of any helpful SWF testing tips. 😉

Written by Vishwanath Krishnamurthi

July 21, 2011 at 5:50 pm

Using Mockito to unit test Spring Webflow

with 6 comments

The flows in Spring Webflow act as powerful controllers. And it is very crucial in a webapp to have the controllers tested.

Unit testing Spring Webflow becomes all the way easier, when a mocking framework is used. And I find Mockito to be pretty good in that arena.

Without much talk, here goes some code:

Step1:
To extend AbstractXmlFlowExecutionTests.

Let’s locate the flow-under-test as such

@Override
 protected FlowDefinitionResource getResource(
 FlowDefinitionResourceFactory resourceFactory) {
 FlowDefinitionResource resource = resourceFactory.createResource("foo-flow.xml");
 Assert.notNull(resource);
 return resource;
 }

Step2:

Mock away the beans used in flow


BazService mockedBazService;

@Override
 protected void registerMockFlowBeans(ConfigurableBeanFactory flowBeanFactory){
 mockedBazService=mock(BazService.class);
flowBeanFactory.registerSingleton("bazService",mockedBazService);
 flowBeanFactory.registerSingleton("barService", mock(BarService.class));
 flowBeanFactory.registerSingleton("MyExceptionHandler", mock(MyExceptionHandler.class));
 }
}

Note that I’m holding the reference for BazBean so I can do some stubbing using Mockito later..
Step3:
Then lets code up a test.

 MockExternalContext context = new MockExternalContext();
 @Test
 public void testFlowShouldEnterStartState()
 {
  this.startFlow(context);
  assertCurrentStateEquals("myFirstState");

 }

How about triggering an event, and checking a transition ?

@Test
 public void testStateWhenFooBarProcessingEventTriggered()
 {

   this.startFlow(context);
   context.setEventId("startProcessingFooBar");
   resumeFlow(context);
   assertCurrentStateEquals("fooBarProcessor");
 }

Some stubbing..

 @Test
 public void testProcessingDetails()
 {
    this.startFlow(context);
    when(mockedBazService
     .isDetailsAvailable(anyString())
     ).thenReturn(true);
    context.setEventId("processDetails");
    resumeFlow(context);
    assertCurrentStateEquals("processDetails");

 }

Enough to get started with testing webflows, I guess. I’ll update more later 🙂

Update:

Some more observations on SWF unit testing.

Written by Vishwanath Krishnamurthi

July 12, 2011 at 10:59 am

How to publish and subscribe to events with Spring ?

leave a comment »

What do we need ?

There are three classes that we’d require:

  1. An event class
  2. A listener
  3. A publisher

Implementation:

  1. With Spring, you can write your own event class by extending ‘ApplicationEvent
  2. A listener is just a bean that implements ‘ApplicationListener
  3. And finally a class that triggers an event –

      >  Here we have choices:

A design tip:

Your listener class would have to implement ApplicationListener. Now it would start listening to all the ApplicationEvents. Rather make it listen only to the concerened event by making it implement ApplicationListener<TheConcernedEvent>.

Type parameters are cool aren’t they ?

A testing tip:

How to trigger the event from JUnit. We need a context, right ?  StaticApplicationContext comes in pretty handy here.

StaticApplicationContext context=new StaticApplicationContext();
context.addApplicationListener(new YourEventListener());
context.refresh();
context.publishEvent(new YourEvent());

With StaticApplicationContext used, we are not forced to load any beans that are not required from a config file. Saves time 🙂


Written by Vishwanath Krishnamurthi

June 15, 2011 at 8:37 pm