Sitemap
SNIGDHO

SNIGDHO

Hi, I’m Snigdho. Love coding and animals.

Testing Spring Controller

7 min readJan 10, 2020

Spring is an open-source framework based on the Java language, and here Controller is a class to handle requests coming from the client. Today we will learn about Spring Controllers and how to test them.

So, what really is Controller? Classically, in Spring MVC, we write a controller class to handle requests coming from the client. Then, the controller summons a business class to deal with business-related tasks and then transmits the client to a logical view name, which is determined by Spring’s transmitter servlet, in order to deliver output. Spring Controller is a special annotation of the @Component annotation.

Controllers

There are many controllers in the Spring MVC module, and each of them is used in specific cases. Some of the controllers are:

  • SimpleFormController:

SimpleFormController is used in the “Form” interface. In form, the user inputs data, edits it, etc. The SimpleFormController is responsible for representing the form, calling a class related to that field, and sending a successful form to the server.

  • AbstractController:

The AbstractController offers caching support. AbstractController can be extended and then implemented as a unique controller from scratch. It should only be used for simple purposes, such as returning a resource to the client without checking request parameters.

  • AbstractCommandController:

AbstractCommandController extends BaseCommandController. Abstract base class for custom command controllers. Auto populates a command bean from the request. For command validation, a validator (property inherited from BaseCommandController ) can be used.

  • CancellableFormController:

CancellableFormController extends SimpleFormController. Extension of SimpleFormController that supports “cancellation” of form processing. By default, this controller looks for a given parameter in the request, identified by the cancelParamKey.

  • MultiActionController:

In the Spring MVC application, MultiActionController is used to group related actions into a single controller. In this way, other controllers that are similar to each other for any purpose can be combined.

  • ParameterizableViewController:

Spring provides the ParameterizableViewController class, which is used for parameterizing view names in a configuration file instead of writing hard-coded view names in the handler method.

  • ServletForwardingController:

ServletForwardingController extends AbstractController implements BeanNameAware. Spring Controller implementation that forwards to a named servlet, i.e., the “servlet-name” in the web. XML rather than a URL path mapping. A target servlet doesn’t even need a “servlet-mapping” on the web.

  • ServletWrappingController:

ServletWrappingController is a class in the Spring API. Useful to invoke an existing servlet via Spring’s dispatching infrastructure, for example, to apply Spring HandlerInterceptors to its requests.

  • UrlFilenameViewController:

UrlFileNameViewController transforms the virtual path of a URL into a view name and returns that view JSP or HTML page. It binds incoming URLs with the View name automatically.

And many more……

OpenMRS is an open-source medical software development organization aiming to help the medical sector with free software & resources. OpenMRS is using Spring MVC framework and the modules can be found in this link. Now I will tell you which controllers are used for what purposes.

Testing Controllers

Here I’ll only tell you the steps for testing a controller.

You can write a Unit Test for testing because it is easy for beginners. There are other ways for testing like Integration Tests, Server, and Client Side Tests, etc.

Here I’ll tell you the steps of the Unit Test in short. You have to find out details on the web.

We can do Unit Testing for a controller method by following the steps:

a) Create the test data which is returned when our service method is called.

b) Configure the used mock object to return the created test data when its findAll() method is called.

c) Execute a GET request to URL ‘/’.

This may seem complex to you as I only mentioned the steps. So, I’ll only demonstrate one Test of a controller. For this example, I’ll be testing SimpleFormController. Let’s start.

Get SNIGDHO’s stories in your inbox

Join Medium for free to get updates from this writer.

In this example I’ll be will be around some Person management system. First, assume we have a Person object :

Then let’s add a service interface allowing basic CRUD operations for a person. If you do not know what CRUD is, then click on CRUD.

Now we want a web interface that will allow the user to save a new Person or to modify an existing person and here comes our SimpleFormController as we are going to use this.

Our controller will be configured in a context file like the below one.

To have our test be able to load a context, we’ll use the JUnit’s @RunWith annotation, and to make our test load our specific context we’ll use the Spring’s @ContextConfiguration annotation.

The @Autowired annotation will do a “by-type” bean injection. This means that since our context contains a single bean of type myProject.web.EditPersonController, that bean (the one we named “/editPerson”) will be injected in the field “controller” at runtime before the test methods are called. But for now, the test just doesn’t compile because we haven’t created the EditPersonController class. So let’s create the controller :

It does nothing for the moment, except allow the test to compile.
To test this newly created controller, we need a HttpServletRequest and a HttpServletResponse object. These objects will be passed to the controller’s handleRequest method. Our test is, of course, not using a servlet engine that is able to create these objects for us, so we have to mock them. Here comes the use of Spring’s MockHttpServletRequest and MockHttpServletResponse classes. With these objects, we can easily simulate an HTTP request that will be forwarded to our controller. We can then verify if a “GET” HTTP call will make our controller send the person form :

The ModelAndView object is used to determine which view the controller chooses to send to the user.
Instead of doing :
assertEquals(controller.getFormView(), mv.getViewName());
We could have done :
import static org.springframework.test.web.ModelAndViewAssert.*;
[...]

assertViewName(mv, controller.getFormView());
[...]

Now the user is provided a form with two input fields. One for the “firstName” and one for the “lastName”. He fills those fields and submits the form. The controller is then called with the “firstName” and “lastName” posted by the user. It must normally save the person and return the “successView” which we named “personSaved” (see the XML context defined previously). Let’s now add this behavior to our test :

So far we’ve tested that while creating a new Person, the user first asks for the Person form (with an HTTP GET call), then submits that form (with an HTTP POST call that details the person’s information), and is redirected to a success page when finished. We can say we tested the navigation part of the “create new Person” use case.

To test that the controller really saved the Person or In other words called the PersonService’s save(Person p) method or not I will use EasyMock to mock a PersonService, tell EasyMock I want this PersonService’s save(Person p) method to be called once with the correct person, and then I will pass that PersonService mock to the controller. Once done, my test will know if the controller really called the PersonService adequately. Here is the code of the test.

To compile, I need to add a PersonService field and its getter/setter in the controller.

Now the test asserts the service has been called correctly. As we run it, we can see it fails with the following message :

java.lang.AssertionError:
Expectation failure on verify:
save(myProject.Person@1f2cea2): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:82)
at org.easymock.EasyMock.verify(EasyMock.java:1410)
...

This just means our controller didn’t call the service’s save method as expected. Let’s make our controller do its job by adding the expected call :

Running the test now should succeed. But, unfortunately, the bar is red again. For time consideration, I’ll leave aside the investigation and go right to the solution: we did not override the equals and hashcode methods of the Person class. Our controller that received the form submission did create a new Person, setting its first and last name. It then passed this new object to the doFormSubmitAction(Object) that called our mock passing the new person. But we told EasyMock we expected our service to be called with another Person object. The default implementation of the equals method in an object makes the following statement false :
(new Person(“Richard”, “Barabé”)).equals(new Person(“Richard”,“Barabé”))

So let’s implement those hashCodes and equals methods.

Press enter or click to view image in full size

Now the code behaves correctly when we have two persons with the same fistName and lastName. And that green bar is back again.

These may seem complex to you but you can find this one and also other & every one of these controllers on the web with examples. As this is a short blog, I just summarized it.

You can also find other & every one of these controllers on the web with examples. As this is a short blog, I just summarized it.

References:

1. https://www.journaldev.com/21515/spring-controller-spring-mvc-controller

2. https://www.baeldung.com/spring-controller-vs-restcontroller

3. https://spring.io/guides/gs/serving-web-content/

4. https://dzone.com/articles/14-tips-for-writing-spring-mvc-controller

5. https://www.roseindia.net/spring/spring-mvc-controller.shtml

7. https://richardbarabe.wordpress.com/2008/08/14/test-driving-a-simpleformcontroller-with-spring-mvc/

6. https://thepracticaldeveloper.com/2017/07/31/guide-spring-boot-controller-tests/

--

--

SNIGDHO
SNIGDHO

Written by SNIGDHO

Hi, I’m Snigdho. Love coding and animals.