Monday, April 29, 2013

Unit testing with PowerMock

In this article I will implement several unit tests using PowerMock framework. This framework is more powerful than other libraries and allows you to mock static methods, private methods and change field properties among other things. I will use the Mockito extension but it also supports EasyMock.

1   Installation

If you use Maven, you can add the following dependencies to your pom.xml:
Otherwise, you can get the libraries here.

2   Preparing the tests

You must add the @RunWith annotation. This annotation will tell JUnit to use the class PowerMockRunner to run the tests.
I'm going to test Foo.class. Using the spy method, all real methods of the class will be invoked except those I mock.

3   Mocking private methods

I want to test methodWithPrivateDependency, but this method internally calls a private method which, let's say, calls an external resource.
The test:
The @PrepareForTest annotation tells PowerMock to prepare the class so it can manipulate it. This is necessary if the class is final, or it contains final, private, static or native methods that should be mocked. In this case, I will need to mock the private method.

If you put this annotation at class level, it will affect all test methods within the class. It would be as follows:

4   Mocking static access

The next method that needs to be tested gets some information by accessing a static method of an inner static class. You need to mock the static access.

The method to test:
The static class:
The test:
I use the @PrepareForTest annotation because I need to mock the static method getData of this class.

5   Mocking chained dependencies

In this example, I want to mock the chainMocks method. There's a singleton Helper class which returns a manager from which the method to test invokes it.
The test:
I only need to prepare Helper class for test because I need to mock its static method getInstance (that's not the case for ConfigurationManager where initializeRegistry is a public instance method).

Wednesday, April 3, 2013

Communication in Spring Webflow 2

1   Introduction

This article tries to complement the reference documentation with examples on how to communicate within a flow in Spring Web flow 2, showing different ways to share data between controllers and views that form a flow. The article is divided into the following sections:
  • Setting flow variables
  • Setting attribute values
  • Using additional scopes
  • Communication with sub flows
  • Communication with other flows
  • Launching events with attributes
  • Accessing RequestContext
  • Accessing Spring beans
  • Using implicit variables

The example explained here uses Spring Web flow 2.3.1 and Spring 3.0.5 versions. You can get the source code here, with all the examples shown in this article.

2   Setting flow variables

There are different ways of setting variables and storing them into the flow scope, where they will then be accessible to controllers and views.

2.1   var element (variable)

The var element instantiates a class and stores it in the flow scope. Since the instance will be stored between flow requests, the class should implement It does not allow you to assign a value, making this element useless for classes without a default constructor (it will crash at runtime with a nice NoSuchMethodException). In that case, you can use the set element (see section 3).

Defining a variable:

You can use this variable in the flow definition, for example, passing it as a parameter to a controller:

The method will receive the car parameter:
Since it is automatically stored in the flow scope, you can also retrieve the value from the request context:
Or use it in the view using for example ${car.color}

2.2   At flow starting point

If your class has no default constructor or you want to retrieve the instance from a service, the element var won't be enough. You can use a controller instead:
In this sample, the information could be retrieved from a service. The result attribute will get the object returned by the controller and store it in the flow scope.

You can also use this approach when entering a state (on-entry) or before rendering a view (on-render).

2.3   Anywhere in the flow

Since you have access to the Web flow RequestContext when invoking a controller, you can set a flow scoped variable as shown below:

3   Setting attribute values

The set element allows you to define an attribute and specify a scope. This element takes the following attributes:
  • name: Scope and name for the attribute, delimited by a dot (
  • value: Value set to the attribute.
  • type: Class type.

For example, you can use it at the beginning of a flow (on-start) or when entering into a state (on-entry). The following sample show how to assign it a specified value when the flow starts:
Or you could set it when launching a transition:

The set element not only allows you to define objects, but also String values. For example, if you have a bean named 'myBean', the first set element in the following sample, will retrieve the Car instance from the bean and store it in the request scope with the name 'carObject'. On the other hand, the second set element will store in the request scope an attribute named 'carString' that will contain the String ''.

You can also use implicit variables when setting the value of the set element (see section 10 for a list of these variables):

4 Using additional scopes

The RequestContext interface contains access to all the other scopes defined in Spring Web flow: request, flash, view, flow and conversation.

You can also access these scopes at flow definition level by using implicit EL variables, which are: requestScope, flashScope, viewScope, flowScope and conversationScope.

For other scopes, you can use the external context:

At flow definition using implicit variables:

Or at controller level through RequestContext interface:

5   Communication with sub flows

When invoking a sub flow from the main flow, you can pass it input attributes. Once the sub flow has finished, it may return output attributes.

The input element allows you to send parameters to the sub flow. When the sub flow starts, these input attributes are stored in the flow scope of the sub flow. You will need to define the input element in the sub flow, using the same name attribute as used in the main flow.

Once the sub flow ends, the main flow can receive output parameters. These output parameters are defined within sub flow's end-states. When the execution returns to the main flow. output parameters will be available as attributes inside the launched event.

Main flow: invoking a sub flow

When returning to the main flow, you will need to define an attribute with the value returned by the sub flow in order to make it accessible to following states.

You could also invoke a controller that would set the value and store it in the needed scope:

Sub flow definition

There are other options to pass information to a subflow which consists in the following:
  • Storing the information at conversation scope (this scope is available from within a flow and its sub flows).
  • Pass the information in the transition which access the sub flow:

6   Communication with other flows

You have two options of passing data to another flow which is not related to the current flow:
  1. Session scoped attributes
  2. URL Request parameters
If you choose the second option, you can do it the following way:

In the view:

When starting the other flow, you can use the requestParameters implicit variable to retrieve the value and store it in the needed scope.

You could also do it in the controller:

Or use the requestParameterMap directly through the getRequestParameters shortcut method:

7   Launching events with attributes

When exiting a controller, it is possible to add attributes to the current event. To do that you need to generate an attribute map.

The controller which launches the event adds the attribute as follows:

8   Accessing the request context

If you want to invoke methods from classes other than controllers, like beans, it is possible to retrieve the web flow request context. There are two ways:

Passing the request context as a parameter to the bean method:

Or you can use the RequestContextHolder class:

9   Accessing Spring beans

If you need to retrieve beans from the Spring context, you can implement a utility class. The following method accesses the Spring context through the web flow request context.

10   Using implicit variables

There's a full list of all available implicit variables at the web flow reference documentation

springsource web flow reference (el-variables)