JUnit testing of Spring MVC application: Testing Spring Webflow

For people in hurry get the latest code from Github and run the below command,


mvn clean test -Dtest=com.example.bookstore.web.controller.CreateOrderTest

In continuation of my earlier blogs on Introduction to Spring MVC and Testing Frontend using Selenium in Spring MVC, in this blog I will demonstrate how to test Web layer in Spring MVC and Spring Web Flow. If you want to measure the quality of JUnit testing of your Spring Web Flow application refer Measuring navigation flow JUnit test in Spring Web flow. There is another blog I have written on JUnit testing Spring Web Flow refer JUnit testing with Spring Webflow.

In this blog I will demo how to build a Spring Web Flow based application using Test driven development (TDD). The use case I will be talking of is a web flow where in user drills down thru few categories and selects few books and select delivery options and place an order.

There is a good introduction of Spring Web Flow here. But just to give a brief introduction about Spring Web Flow, it is composed of a set of states. A state is a point in the flow where some event happens: for instance showing books list for a category or adding the books to the shopping cart. Each state has one or more transitions that are used to move to another state. A transition is triggered by an event.

As a first step, please refer this createOrders-flow.xml, if you notice carefully OrderForm is stored in the flowScope. And this object carries the state between each step. Let us see the bootstrapping process in JUnit test as below,

public class CreateOrderTest extends AbstractXmlFlowExecutionTests {
private OrderController orderController;

protected void setUp() {
orderController = Mockito.mock(OrderController.class);
}

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

@Override
protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) {
return resourceFactory.createFileResource("src/main/webapp/WEB-INF/view/public/createOrders/createOrders-flow.xml");
}

//JUnit tests below
}

If you notice this class is subclassed from a class AbstractXmlFlowExecutionTests, it has 3 overridden methods, setup, configureFlowBuilderContext, getResource. getResource method is the one where we set the createOrders-flow.xml and is returned for testing. If you also notice we have used Mockito to mock OrderController and register the bean in the flow XML.

Let us start building the JUnit test to test each node (view-state) of the flow. For starting the flow you need to do as below,

public void testStartCreateOrderFlow() {

MutableAttributeMap input = new LocalAttributeMap();
MockExternalContext context = new MockExternalContext();
startFlow(input, context);

Mockito.verify(orderController, VerificationModeFactory.times(1)).initializeForm();
Mockito.verify(orderController, VerificationModeFactory.times(1)).initializeSelectableCategories();

assertCurrentStateEquals("selectCategory");
assertResponseWrittenEquals("selectCategory", context);
}

If you notice carefully in the flow, we are asking the controller to call the initializeForm at on-start event and call initializeSelectableCategories at on-render of selectCategory view-state.

Using Mockito we are verifying if the initializeForm and initializeSelectableCategories called once only. And finally we assert for the next state.

Similarly we test other view states.

Finally we test calling a subflow by mocking the subflow, refer createMockBookingSubflow below you will get the idea. If you want to understand more refer Mocking a subflow.


public void testSelectDeliveryOptions_AddAndNext() {

setCurrentState("selectDeliveryOptions");
 getFlowScope().put("orderForm", createTestOrderForm());
 getFlowDefinitionRegistry().registerFlowDefinition(createMockBookingSubflow());

MockExternalContext context = new MockExternalContext();
 context.setEventId("finish");
 resumeFlow(context);
 }

private Flow createMockBookingSubflow() {
 Flow mockBookingFlow = new Flow("secured/placeOrders");
 mockBookingFlow.setInputMapper(new Mapper() {
 public MappingResults map(Object source, Object target) {
 // assert that 1L was passed in as input
 return null;
 }
 });
 // immediately return the bookingConfirmed outcome so the caller can respond
 new EndState(mockBookingFlow, "endOrderOk");
 return mockBookingFlow;
 }

I hope this blog helped you. In my next blog I will be taking about integrating Kickstrap with Spring MVC application.

Reference:

Pro Spring MVC: With Web Flow by by Marten Deinum, Koen Serneels

About these ads

One thought on “JUnit testing of Spring MVC application: Testing Spring Webflow

  1. Pingback: JUnit testing of Spring MVC application – Introduction | Krishna's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s