Spring MVC Controller Unit Tests: "Normal" Controllers (2023)

The first part of this tutorial covered how to set up unit tests using the Spring MVC testing framework. Now it's time to get your hands dirty and learn how to write unit tests for "normal" controllers.

The next obvious question is:

What is a normal driver?

Well, a regular controller (in the context of this blog post) is a controller that renders a view or handles a form submission.

Let us begin.

Use: It is recommended that you read the first part of this tutorial before reading this blog post (if you have already read it, you can continue reading)

Use Maven to get the required dependencies

We can get the required test dependencies by adding the following dependency declarations to the sample application's POM file:

(Video) Unit Testing of Spring MVC Controllers: Normal Controllers

  • Jackson 2.2.1 (base and data link modules). We use Jackson to turn the object into an encoded URLlineObject.
  • Hamcrest 1.3. When we write assertions for answers we use hamcrest matchers.
  • JUnit 4.11 (without the Hacrest kernel dependency).
  • Mockito 1.9.5
  • Spring Test 3.2.3 released

The relevant part of the pom.xmlFile looks like this:

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><Version>2.2.1</Version><scope>test</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>Jackson-bind de data</artifactId><Version>2.2.1</Version><scope>test</scope></dependency><dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest-todo</artifactId><Version>1.3</Version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><Version>4.11</Version><scope>test</scope><Exclusions><exclusion><artifactId>hamcrest-core</artifactId><groupId>org.hamcrest</groupId></disclaimer></Exclusions></dependency><dependency><groupId>org.mockito</groupId><artifactId>Mockito-Core</artifactId><Version>1.9.5</Version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>Spring test</artifactId><Version>3.2.3.RELEASE</Version><scope>test</scope></dependency>

Let's jump ahead and see how to write unit tests for Spring MVC controllers using the Spring MVC testing framework.

Write unit tests for controller methods

Each unit test we write to test the behavior of a controller method consists of the following steps:

  1. We send a request to the tested controller method.
  2. We confirm that we received the expected response.

The Spring MVC testing framework has a few "core" classes that we can use to implement these steps in our tests. These classes are described below:

  • We can use the static methods of theMockMvcRequestBuildersClass for generating requests. More specifically, we can create a request generator and then pass it as a method parameter to the method making the actual request.
  • El MockMvcThe class is the main entry point for testing. We can make a request by calling youRealizar (RequestBuilder-RequestBuilder)Method.
  • We can write statements about the received response using the static methods ofClase MockMvcResultMathers.

Next, let's look at some examples that show how these classes are used in unit tests. We will write unit tests for the following controller methods:

  • The first controller method displays a page that displays a task list.
  • The second controller method returns a page showing information about a single pending task.
  • The third controller method handles the form submission used to add a new task to the database.

Render the todo list page

First, let's look at the implementation of the controller method used to render the task list page.

expected behavior

Implementing the controller method to display all to-do information involves the following steps:

  1. Gets the outstanding items by callingfind all()method ofAllServiceinterface . This method returns a list ofatobjects.
  2. Adds the received list to the model.
  3. Returns the name of the rendered view.

The relevant part of the TodoControllerthe class looks like this:

importar org.springframework.stereotype.Controller;import org.springframework.ui.Model;importar org.springframework.web.bind.annotation.*;import java.util.List;@Rulespublic class TodoController {private final TodoService service; @RequestMapping(valor = "/", Methode = RequestMethod. GET)public String findAll(Modell model) {List <All> Models = Service. find all();model.addAttribute("all", Models);return "all/list";}}

Now we're ready to write unit tests for this method. Let's see how we can do that.

Quiz: find tasks

We can write a unit test for this controller method using the following steps:

(Video) Unit Testing of Spring MVC Controllers: Configuration

  1. Create the test data that will be returned when our service method is called. When creating test data for testing, we use a concept called test data generator.
  2. Configure the mock object used to return the test data created when yourThe findAll() method is called.
  3. perform aTO GETRequest to send URL '/'.
  4. Be sure to return HTTP status code 200.
  5. Ensure that the returned view is named "all/list".
  6. Make sure the request is redirected to the URL "/WEB-INF/jsp/todo/list.jsp".
  7. Make sure the model property namedatcontains two elements.
  8. Make sure that the called model propertyatcontains the correct elements.
  9. Make sure the simulated objectfind all()The method is only called once.
  10. Ensure that no other methods of the mock object are called during the test.

The source code of our unit tests looks like this:

import org.junit.Before;import org.junit.Test;importar org.junit.runner.RunWith;import org.mockito.Mockito;importar org.springframework.beans.factory.annotation.Autowired;importar org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;importar org.springframework.test.context.web.WebAppConfiguration;importar org.springframework.test.web.servlet.MockMvc;importar org.springframework.test.web.servlet.setup.MockMvcBuilders;importar org.springframework.web.context.WebApplicationContext;import java.util.Arrays;import static org.hamcrest.Matchers.*;import static org.hamcrest.Matchers.is;import org.mockito.Mockito.* static;importar org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get estático;Import estático org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;importar org.springframework.test.web.servlet.result.MockMvcResultMatchers.model estático;@RunWith(SpringJUnit4ClassRunner. Class)@ContextConfiguration(Classes = {TestContext. Class, WebAppContext. Class})@WebAppSettingspublic class TodoControllerTest {private MockMvc mockMvc;@autoverdrahtetprivate TodoService todoServiceMock;//Add the WebApplicationContext field here//The setUp() method is skipped.@Testpublic void findAll_ShouldAddTodoEntriesToModelAndRenderTodoListView() throws exception {All first = new TodoBuilder().id(1L).description("Learn by yourself").title("Foo").to build();All second = new TodoBuilder().id(2L).description("Learn by yourself").Titelleiste").to build();when(todoServiceMock.findAll()).thenReturn(Arrays.asList(first, second));mockMvc.perform(obtener("/")).andExpect(status().isOk()).andExpect(view().name("alle/liste")).andExpect(URL forwarded ("/WEB-INF/jsp/todo/list.jsp")).andExpect(model().attribute("all", hasSize(2))).andExpect(modelo().attribute("todos", hasItem(at(hasProperty("id", es(1L)),hasProperty("Description", is("The property itself")),hasProperty("Title", is("Foo")))))).andExpect(modelo().attribute("todos", hasItem(at(hasProperty("id", es(2L)),hasProperty("Description", is("The property itself")),hasProperty("Title", is("Bar"))))));check(allServiceMock, times(1)).findAll();checkNoMoreInteractions(todoServiceMock);}}

Render start page Show all

Before we can write actual unit tests for a controller method, we need to take a closer look at the method's implementation. Let's go ahead and see how the controller is implemented.

expected behavior

Implement the Controller method to display information about each task by doing the following:

  1. Gets the requested pending task by callingfindById() method ofAllServiceinterface and passes the ID of the requested task as a method parameter. This method returns the pending item found.This method throws TodoNotEntryNotFoundExceptionif no task entry is found.
  2. Adds the pending items found to the model.
  3. Returns the name of the rendered view.

The source code of our controller method looks like this:

importar org.springframework.stereotype.Controller;import org.springframework.ui.Model;importar org.springframework.web.bind.annotation.*;@Rulespublic class TodoController {private final TodoService service;@RequestMapping(value = "/all/{id}", method = RequestMethod.GET)public String findById(@PathVariable("id") Long id, Model model) throws TodoNotFoundException {All found = service.findById(id);model.addAttribute("all", found);return "do/see";}}

Our next question is:

What happens when the TodoEntryNotFoundException exception is thrown?

In the previous part of this tutorial, we created an exception resolver bean to handle exceptions thrown by controller classes. The bean configuration looks like this:

@Beanpublic SimpleMappingExceptionResolverExceptionResolver() {SimpleMappingExceptionResolverExceptionResolver = new SimpleMappingExceptionResolver();PropertiesExceptionMappings = new properties();ExceptionMappings.put("net.petrikainulainen.spring.testmvc.todo.exception.TodoNotFoundException", "error/404");exception assignments. put("java.lang.Exception", "error/error");exception assignments. put("java.lang.RuntimeException", "error/error");ExceptionResolver.setExceptionMappings (ExceptionMappings);Property status codes = newproperties();status codes. put("Error/404", "404");status codes. put("Error/Error", "500");excepciónResolver.setStatusCodes(statusCodes);returns the exception handler;}

As we can see when aTodoEntryNotFoundExceptionis launched, our application displays the "Error/404" view and returns HTTP status code 404.

Obviously we need to write two tests for this controller method:

  1. We need to write a test to ensure our app behaves correctly when no to do items are found.
  2. Once we've found our backlog, we need to write a test to verify that our application is working properly.

Let's see how to write these tests.

(Video) Spring Mvc unit test using Mockito + MockMVC | Java Techie

Test 1: All items not found

First we need to make sure our app works if the requested task item is not found. We can write tests to ensure this as follows:

  1. Configure the mockup to start aTodoNotFoundExceptionWhen isThe findById() method isI calland the ID of the requested pending item is 1L .
  2. run aTO GETRequest to send URL '/todo/1'.
  3. Check if HTTP status code 404 was returned.
  4. Ensure that the returned view is named "error/404".
  5. Be sure to redirect the request to the URL "/WEB-INF/jsp/error/404.jsp".
  6. Make sure that the findById() method of theAllServicethe interface is only called once with the correct method parameters (1L) .
  7. Make sure that no other methods of the mock object are called during this test.

The source code of our unit tests looks like this:

import org.junit.Before;import org.junit.Test;importar org.junit.runner.RunWith;import org.mockito.Mockito;importar org.springframework.beans.factory.annotation.Autowired;importar org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;importar org.springframework.test.context.web.WebAppConfiguration;importar org.springframework.test.web.servlet.MockMvc;importar org.springframework.test.web.servlet.setup.MockMvcBuilders;importar org.springframework.web.context.WebApplicationContext;import org.mockito.Mockito.* static;importar org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get estático;Import estático org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringJUnit4ClassRunner. Class)@ContextConfiguration(Classes = {TestContext. Class, WebAppContext. Class})@WebAppSettingspublic class TodoControllerTest {private MockMvc mockMvc;@autoverdrahtetprivate TodoService todoServiceMock;//Add the WebApplicationContext field here//The setUp() method is skipped.@Testpublic void findById_TodoEntryNotFound_ShouldRender404View() throws exception {when(todoServiceMock.findById(1L)).thenThrow(new TodoNotFoundException(""));mockMvc.perform(get("/todo/{id}", 1L)).andExpect(status().isNotFound()).andExpect(view().name("error/404")).andExpect(forwardedUrl("/WEB-INF/jsp/error/404.jsp"));check(allServiceMock, times(1)).findById(1L);verificarZeroInteractions(todoServiceMock);}}

Test 2: Find the All entry

Second, we need to write a test to make sure the controller works when the task is found. We can do this by following these steps:

  1. create theat-Object returned when our service method is called. Again, we use the test data generator to create the returned onesatObject.
  2. Set our mock object to return the created oneatobject if it isThe findById() method is called with the method parameter 1L.
  3. run aTO GETRequest to send URL '/todo/1'.
  4. Verify that HTTP status code 200 is returned.
  5. Make sure the returned view name is "todo/view".
  6. Be sure to redirect the request to the URL "/WEB-INF/jsp/todo/view.jsp".
  7. Check the identificationof the named model objectatis 1L.
  8. Check the descriptionof the named model objectatit is "the law itself."
  9. Check if thetitleof the named model objectatis "foo".
  10. Make sure that only the dummy object's findById() is calledMethod with the correct method arguments (1L) .
  11. Ensure that no other methods of the mock object are called during the test.

The source code of our unit tests looks like this:

import org.junit.Before;import org.junit.Test;importar org.junit.runner.RunWith;import org.mockito.Mockito;importar org.springframework.beans.factory.annotation.Autowired;importar org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;importar org.springframework.test.context.web.WebAppConfiguration;importar org.springframework.test.web.servlet.MockMvc;importar org.springframework.test.web.servlet.setup.MockMvcBuilders;importar org.springframework.web.context.WebApplicationContext;Import static org.hamcrest.Matchers.hasProperty;import static org.hamcrest.Matchers.is;import org.mockito.Mockito.* static;importar org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get estático;Import estático org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringJUnit4ClassRunner. Class)@ContextConfiguration(Classes = {TestContext. Class, WebAppContext. Class})@WebAppSettingspublic class TodoControllerTest {private MockMvc mockMvc;@autoverdrahtetprivate TodoService todoServiceMock;//Add the WebApplicationContext field here//The setUp() method is skipped.@Testpublic void findById_TodoEntryFound_ShouldAddTodoEntryToModelAndRenderViewTodoEntryView() throws exception {Todo found = new TodoBuilder().id(1L).description("Learn by yourself").title("Foo").to build();when(todoServiceMock.findById(1L)).thenReturn(encontrado);mockMvc.perform(get("/todo/{id}", 1L)).andExpect(status().isOk()).andExpect(view().name("do/view")).andExpect(URL forwarded ("/WEB-INF/jsp/todo/view.jsp")).andExpect(modelo().attribute("todo", hasProperty("id", is(1L)))).andExpect(model().attribute("everything", hasProperty("description", is("The property itself")))).andExpect(model().attribute("todo", hasProperty("title", is("Foo"))));check(allServiceMock, times(1)).findById(1L);checkNoMoreInteractions(todoServiceMock);}}

Edit form submissions for the Add All input form

Again, let's look at the expected behavior of controller methods before writing unit tests for them.

expected behavior

Implement the controller method that handles the submission of the Add Task input form by doing the following:

  1. Check the BindingResultThe object specified as a method parameter is healthy. If an error is found, the form view name is returned.
  2. Add a new All entry by callingadd() method ofAllServiceinterface , with the form object being passed to the method as a parameter. This method creates and returns a new pending item.
  3. Create a feedback message about the added to-do item and add this message to theRedirect AttributesObject specified as method parameter.
  4. Adds the ID of the added pending item to theRedirect AttributesObject.
  5. Returns the name of the redirection view that redirects the request to the task view input page.

The relevant part of the TodoControllerthe class looks like this:

importar org.springframework.context.MessageSource;importar org.springframework.context.i18n.LocaleContextHolder;importar org.springframework.stereotype.Controller;importar org.springframework.validation.BindingResult;importar org.springframework.web.bind.annotation.*;importar org.springframework.web.servlet.mvc.support.RedirectAttributes;javax.validation.Valid importieren;import java.util.Locale;@Rules@SessionAttributes("todo")public class TodoController {private final TodoService service;news source end private news source;@RequestMapping(value = "/all/add", method = RequestMethod. POST)public String add(@Valid @ModelAttribute("todo") TodoDTO dto, result of BindingResult, attributes of RedirectAttributes) {if (result. has error()) {returns "all/add";}Everything added = service. add (discount);addFeedbackMessage(Attributes, "Feedback. Message. Pending. Added", Added. getTitle());Attributes addAttribute("id", added. getId());return createRedirectViewPath("todo/ver");}private void addFeedbackMessage(Attribute de RedirectAttributes, String messageCode, Object... messageParameters) {String localizadoFeedbackMessage = getMessage (messageCode, messageParameters);atributos.addFlashAttribute("feedbackMessage", localizadoFeedbackMessage);}private String getMessage(string message code, object... message parameters) {Current locale = LocaleContextHolder. getLocal();return messageSource.getMessage (messageCode, messageParameters, aktuell);}Cadena privada createRedirectViewPath(String requestMapping) {StringBuilder RedirectViewPath = new StringBuilder();RedirectViewPath.append("Redirect:");forwardViewPath.append (requestMapping);devuelve RedirectViewPath.toString();}}

As we can see, the controller method uses theTodoDTOobject as a form object.All DTOclass is a simple DTO class whose source code is as follows:

importar org.hibernate.validator.constraints.Length;import org.hibernate.validator.constraints.NotEmpty;public class TodoDTO {private lange ID;@Length (max = 500)private string description;@not empty@Long (max = 100)private string title;//Constructor and other methods are ignored.}

All DTOThe class declares some validation constraints, which are described below:

  • The task title cannot be empty.
  • The maximum length of the description is 500 characters.
  • The maximum length of the title is 100 characters.

Looking at the tests written for this controller method, it is clear that we need to ensure this

(Video) Unit Testing of Spring MVC Controllers: REST API

  1. If validation fails, the controller method is a job property.
  2. The controller method is owned by the job when the task item is added to the database.

Let's see how to write these tests.

Test 1: Validation failed

First we need to write a test to make sure our controller method works correctly when validation fails. We can write this test as follows:

  1. A... createtitlewith 101 characters.
  2. Create a 501 characterdesignation.
  3. Create a new TodoDTOObject with our test data generator. set objecttitlejdesignation.
  4. do oneTO POSTRequest to send "all/add" url. Set the request content type to "application/x-www-form-urlencoded". Make sure the content of our form object is sent in the request body. Set the form object to session.
  5. Verify that HTTP status code 200 is returned.
  6. Confirm that the view name returned is "all/add".
  7. Make sure the request is redirected to the URL "/WEB-INF/jsp/todo/add.jsp".
  8. Validate the properties of our model for field errors in thetitlejdescription fields.
  9. Pay attention to the identificationof our property model is null.
  10. Pay attention to the descriptionof the properties of our model is correct.
  11. Pay attention to the titleof the model property is correct.
  12. Ensure that the mock object's methods are not called during the test.

The source code of our unit tests looks like this:

import org.junit.Before;import org.junit.Test;importar org.junit.runner.RunWith;import org.mockito.Mockito;importar org.springframework.beans.factory.annotation.Autowired;importar org.springframework.http.MediaType;importar org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;importar org.springframework.test.context.web.WebAppConfiguration;importar org.springframework.test.web.servlet.MockMvc;importar org.springframework.test.web.servlet.setup.MockMvcBuilders;importar org.springframework.web.context.WebApplicationContext;Import static org.hamcrest.Matchers.hasProperty;import static org.hamcrest.Matchers.is;import org.hamcrest.Matchers.nullValue static;import org.mockito.Mockito.* static;import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.static post;Import estático org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringJUnit4ClassRunner. Class)@ContextConfiguration(Classes = {TestContext. Class, WebAppContext. Class})@WebAppSettingspublic class TodoControllerTest {private MockMvc mockMvc;@autoverdrahtetprivate TodoService todoServiceMock;//Add the WebApplicationContext field here//The setUp() method is skipped.@Testpublic void add_DescriptionAndTitleAreTooLong_ShouldRenderFormViewAndReturnValidationErrorsForTitleAndDescription() arroja una excepción {String Title = TestUtil.createStringWithLength(101);String Description = TestUtil. createStringWithLength(501);TodoDTO formObject = neuer TodoDTOBuilder().description(description).title(Titel).to build();mockMvc.perform(post("/do/add").contentType(Medientyp.APPLICATION_FORM_URLENCODED).content(TestUtil.convertObjectToFormUrlEncodedBytes(formObject)).sessionAttr("alle", formObject)).andExpect(status().isOk()).andExpect(view().name("all/add")).andExpect(URL forwarded ("/WEB-INF/jsp/todo/add.jsp")).andExpect(pattern().attributeHasFieldErrors("all", "title")).andExpect(model().attributeHasFieldErrors("do", "description")).andExpect(modelo().attribute("todo", hasProperty("id", nullValue()))).andExpect(model().attribute("alles", hasProperty("description", is(description)))).andExpect(pattern().attribute("alles", hasProperty("title", is(title))));verificarZeroInteractions(todoServiceMock);}}

Our test cases call some static methods of theTestUtil Class.These methods are described below:

  • The createStringWithLength(int length) method creates a new onelineObject with the given length and returns the created object.
  • convertObjectToFormUrlEncodedBytes(object object)The method converts an object into a URL-encoded form.lineobject and returns the content of thelineobject like aByteFormation.

The TestUtil source codeClass is as follows:

importar com.fasterxml.jackson.annotation.JsonInclude;importar com.fasterxml.jackson.databind.ObjectMapper;import java.util.Iterator;import java.util.Map;import java.util.Set;public class TestUtil {public static byte[] convertObjectToFormUrlEncodedBytes(Objekt Objekt) {Mappeador de ObjectMapper = new ObjectMapper();asignador.setSerializationInclusion(JsonInclude.Include.NON_NULL);Map<String, Objekt> propertyValues ​​= mapper.convertValue(object, Map.class);Set<String> propertyNames = propertyValues. keyset();Iterator<String> nameIter = propertyNames. iterador();StringBuilder formUrlEncoded = new StringBuilder();for (int index=0; index < propertyNames. size(); index++) {chain currentKey = nameIter. next();Object current value = property values. get(current key);formUrlEncoded.append (claveActual);formUrlEncoded.append("=");formUrlEncoded.append(current value);if (nombreIter. hasNext()) {formUrlEncoded.append("&");}}devuelve formUrlEncoded.toString().getBytes();}public static string createStringWithLength(int length) {Konstruktor StringBuilder = new StringBuilder();for (int index = 0; index < length; index++) {Konstruktor.append("a");}volver constructor.toString();}}

Test 2: Todo entry added to database

Second, we need to write a test to make sure the controller works properly when a new task is added to the database. We can write this test as follows:

  1. Create a form object using the test data generator class. Set the value to "legal".titlejdesignationFields of the created object.
  2. A... createatObject returned when theAdd()method ofAllServiceis called interface.
  3. Set our mock object to return what was createdAny object if it isAdd()The method is called and the generated form object is passed as a method parameter.
  4. do oneTO POSTRequest to send "all/add" url. Set the request content type to "application/x-www-form-urlencoded". Make sure the content of our form object is sent in the request body. Set the form object to session.
  5. Check if HTTP status code 302 was returned.
  6. Ensure that the returned view is named "redirect:todo/{id}".
  7. Be sure to redirect the request to the URL "/todo/1".
  8. Verify that the named model attributeI WOULDis "1".
  9. Make sure feedback is configured.
  10. Check if our mock objectAdd()The method is called only once, and the form object is provided as a parameter to the method.
  11. Make sure that no other methods of the mock object were called during the test.

The source code of our unit tests looks like this:

import org.junit.Before;import org.junit.Test;importar org.junit.runner.RunWith;import org.mockito.Mockito;importar org.springframework.beans.factory.annotation.Autowired;importar org.springframework.http.MediaType;importar org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;importar org.springframework.test.context.web.WebAppConfiguration;importar org.springframework.test.web.servlet.MockMvc;importar org.springframework.test.web.servlet.setup.MockMvcBuilders;importar org.springframework.web.context.WebApplicationContext;import static org.hamcrest.Matchers.is;import org.mockito.Mockito.* static;import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.static post;Import estático org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringJUnit4ClassRunner. Class)@ContextConfiguration(Classes = {TestContext. Class, WebAppContext. Class})@WebAppSettingspublic class TodoControllerTest {private MockMvc mockMvc;@autoverdrahtetprivate TodoService todoServiceMock;//Add the WebApplicationContext field here//The setUp() method is skipped.@Testpublic void add_NewTodoEntry_ShouldAddTodoEntryAndRenderViewTodoEntryView() throws exception {TodoDTO formObject = neuer TodoDTOBuilder().description("description").title("Titel").to build();Added todo = new TodoBuilder().id(1L).description(formObject.getDescription()).title(formObject.getTitle()).to build();when(todoServiceMock.add(formObject)).thenReturn(agregado);mockMvc.perform(post("/do/add").contentType(Medientyp.APPLICATION_FORM_URLENCODED).content(TestUtil.convertObjectToFormUrlEncodedBytes(formObject)).sessionAttr("alle", formObject)).andExpect(status().isMovedTemporally()).andExpect(view().name("redirect:todo/{id}")).andExpect(redirectedUrl("/todo/1")).andExpect(model().attribute("id", is("1"))).andExpect(flash().attribute("feedbackMessage", is("Feedback from All: added title.")));verificar(todoServiceMock, times(1)).add(formObject);checkNoMoreInteractions(todoServiceMock);}}

Continue

We've now written some unit tests for "normal" controller methods using the Spring MVC testing framework. This tutorial teaches four things:

  • We learned to create requests that are processed by controller best practices.
  • We learned how to write assertions for the responses returned from the tested controller methods.
  • We learned how to write unit tests for controller methods that render views.
  • We learned how to write unit tests for controller methods that handle form submissions.

The next part of this tutorial describes how to write unit tests for REST APIs.

PS The sample app for this blog post is available on Github. I suggest you check it out as it contains some unit tests that are not covered in this blog post.

(Video) How to Test Controller Layer in Spring Boot

Relation:Unit Testing Spring MVC Controllers – “Normal” Controllers by our JCG partner Petri Kainulainen on Petri Kainulainen's blog.


Translated from: https://www.javacodegeeks.com/2013/07/unit-testing-of-spring-mvc-controllers-normal-controllers.html

FAQs

How to write unit test for controller in Spring MVC? ›

How to unit test Controllers in Spring MVC
  1. Importing Static Tool Methods.
  2. Initialize MockMvc.
  3. Execute tests. Test GET interface. Testing the POST interface. Test file upload.
  4. Define the expected result.
  5. Write at the end.
Feb 16, 2022

Should controllers have unit tests? ›

Controller logic can be tested using automated integration tests, separate and distinct from unit tests for individual components. -1: A unit test for a controller could be pointless. Controllers are about transformation, but sometimes the transformation itself is complex and a developer may want to have it covered.

What is the difference between @REST controller and @controller? ›

The main difference between the @restcontroller and the @controller is that the @restcontroller combination of the @controller and @ResponseBody annotation.

How to unit test a controller in Spring Boot? ›

How to test a controller in Spring Boot - a practical guide
  1. MockMVC standalone code example.
  2. MockitoExtension and MockMVC.
  3. JacksonTester initialization.
  4. Configure the Standalone Setup in MockMVC.
  5. Testing ControllerAdvice and Filter with MockMVC.
  6. Better Assertions with BDDMockito and AssertJ.
Oct 9, 2021

What is the difference between @WebMvcTest and @SpringBootTest? ›

The main difference between @SpringBootTest and @WebMvcTest annotations is that @SpringBootTest annotation will start the full application context. Whereas @WebMvcTest annotation will make Spring Framework create application context with a limited number of beans(only those related to the Web Layer).

What is the easiest method to write a unit test in spring? ›

java. Spring Boot provides an easy way to write a unit test for Rest controller. With the help of SpringJUnit4ClassRunner and MockMVC, a web application context can be created to write unit test for Rest controller. First, we add the necessary annotations to our test class as in the previous test.

Why unit testing is not enough? ›

Unit tests do not check the integration between all the functional components of the application. They are, in fact, furthest from the end user experience. Today, you need to test the application end-to-end to drive quality.

Should I write unit tests for everything? ›

The answer to the more general question is yes, you should unit test everything you can. Doing so creates a legacy for later so changes down the road can be done with peace of mind. It ensures that your code works as expected. It also documents the intended usage of the interfaces.

What should you avoid in unit testing? ›

Final Thoughts
  • writing tests for every part of the functionality instead of every function.
  • not obsessing over code coverage, but focusing on testing risky code.
  • minimizing setup and mocking code.
  • making sure your tests can fail.
  • keeping non-determinism out of your tests.
Sep 28, 2021

Can we replace @RestController with @controller? ›

So if you are using latest spring version you can directly replace @Controller with @RestController without any issue.

Why do we use @autowired annotation? ›

Spring @Autowired annotation is used for automatic dependency injection. Spring framework is built on dependency injection and we inject the class dependencies through spring bean configuration file.

What is the difference between @PathVariable and @RequestParam? ›

2) @RequestParam is more useful on a traditional web application where data is mostly passed in the query parameters while @PathVariable is more suitable for RESTful web services where URL contains values.

How do you check if all controller buttons are working? ›

Test game controller input
  1. Connect your game controller to your PC.
  2. If you hear the installing hardware chime on Windows 10, allow drivers for it to install.
  3. Open your browser and visit Gamepad Tester.
  4. Press any button on the controller to wake it up.
  5. The controller will be detected by Gamepad Tester.
Nov 18, 2020

Can you unit test controllers? ›

Unit testing controllers. Set up unit tests of controller actions to focus on the controller's behavior. A controller unit test avoids scenarios such as filters, routing, and model binding. Tests that cover the interactions among components that collectively respond to a request are handled by integration tests.

What is the difference between controller and rest controller in Spring boot? ›

@Controller is used to mark classes as Spring MVC Controller. @RestController annotation is a special controller used in RESTful Web services, and it's the combination of @Controller and @ResponseBody annotation. It is a specialized version of @Component annotation.

What is difference between @PathVariable and @RequestParam in Spring Boot? ›

Encoded vs Exact Value

Because @PathVariable is extracting values from the URI path, it's not encoded. On the other hand, @RequestParam is encoded.

What is the difference between @ComponentScan and @EnableAutoConfiguration in Spring Boot? ›

The main difference between these annotations is that @ComponentScan scans for Spring components while @EnableAutoConfiguration is used for auto-configuring beans present in the classpath in Spring Boot applications.

What is difference between @EnableAutoConfiguration and SpringBootApplication? ›

The @SpringBootApplication is a combination of three annotations @Configuration (used for Java-based configuration), @ComponentScan (used for component scanning), and @EnableAutoConfiguration (used to enable auto-configuration in Spring Boot).

Why is writing unit tests so hard? ›

Developers experience Unit Testing as difficult when they run into these kinds of problems: Classes are tightly coupled to other classes, which makes it hard to test because you need to control those other classes as well when you are writing your tests. This is very, very difficult and very error prone.

How do I get better at writing unit tests? ›

How to better write unit tests
  1. 1 - Use descriptive test naming.
  2. 2 - Make sure your unit tests are reliable.
  3. 3 - Don't rely solely on coverage.
  4. 4 - Mock with caution.
  5. 5 - Make your tests run fast.
Jul 13, 2022

How do you write faster in unit testing? ›

In order to produce deadly fast tests, you must avoid overly complex or bloated configuration, for example by loading Spring context with @RunWith(SpringJUnit4ClassRunner. class) . Unit tests must run quickly and they should be easily repeatable. Avoid loading contexts!

How much unit testing is enough? ›

While there is no standard for unit testing, one number often cited in the testing world is 80%. "Eighty percent is what I usually see as the gating standard for code coverage in corporate shops," said Tim Ottinger, a senior consultant at Industrial Logic. "Any higher or lower than that is unusual."

How much unit test coverage is enough? ›

Minimum Test Coverage Rate: Keeping it between 60 - 70%. Optimal Test Coverage Rate: Keeping it between 70 - 80%. Overkill Test Coverage Rate: Keeping it between 80 - 100%. N.B: The above are my personal opinion and it may vary depending upon specific system design or requirements.

Should unit tests only test one thing? ›

Unit tests are also subject to the single-responsibility principle. Each test case should cover one thing and one thing only. That doesn't mean that it should have only a single assert statement, just that it should verify one aspect of expected behavior.

Who is the best person to write unit tests? ›

Unit Testing Is the Developers Job

Yes, developers typically write unit tests. However, they are largely responsible for writing these tests to ensure that the code works – most developer tests are likely to cover happy-path and obvious negative cases.

Is there such a thing as too many unit tests? ›

Yes, it is possible to have too many unit tests. If you have 100% coverage with unit tests and no integration tests for example, you have a clear issue. Some scenarios: You over-engineer your tests to a specific implementation.

How much time does it take to write unit tests? ›

The typical time budgeted on writing unit tests is about 1 day for every feature that takes 3-4 days of heads-down coding. But that can vary with a lot of factors.

Which three items are best practices for unit tests? ›

The name of your test should consist of three parts:
  • The name of the method being tested.
  • The scenario under which it's being tested.
  • The expected behavior when the scenario is invoked.
Nov 4, 2022

What are the three essential A's related to unit testing? ›

A unit test typically features three different phases: Arrange, Act, and Assert (sometimes referred to as AAA). For a unit test to be successful, the resulting behavior in all three phases must be in line with expectations.

Should unit test cover all cases? ›

It isn't realistic -- or necessary -- to expect 100% code coverage through unit tests. The unit tests you create depend on business needs and the application or applications' complexity. Aim for 95% or higher coverage with unit tests for new application code.

What happens if I use @component instead of controller? ›

Even if you replace @Controller annotation with @Compoenent, Spring can automatically detect and register the controller class but it may not work as you expect with respect to request mapping. You can further see, Spring Master Class course on Udemy for more details about these annotations.

Should I use @controller or @RestController? ›

Just remember that @Controller is used to create web controllers that return views, which is further resolved by view resolver, while @RestController is used to create web services that return JSON or XML data. It's also worth noting.

Can we replace @component with @controller? ›

There is no difference between @Component , @Service , @Controller , @Repository . @Component is the Generic annotation to represent the component of our MVC.

What is difference between @inject and @autowired annotation? ›

@Inject and @Autowired both annotations are used for autowiring in your application. @Inject annotation is part of Java CDI which was introduced in Java 6, whereas @Autowire annotation is part of spring framework. Both annotations fulfill same purpose therefore, anything of these we can use in our application. Sr.

What is the difference between @qualifier and Autowired? ›

The difference are that @Autowired and @Qualifier are the spring annotation while @Resource is the standard java annotation (from JSR-250) . Besides , @Resource only supports for fields and setter injection while @Autowired supports fields , setter ,constructors and multi-argument methods injection.

What is the disadvantage of Autowired? ›

There are three weaknesses of autowiring : Overriding: You can still specify dependencies using <constructor-arg> and <property> settings which will always override @Autowired . Primitive data types: Autowiring can't be used to inject primitive and string values. It works with reference only.

What is difference between @RequestBody and @ResponseBody? ›

By using @RequestBody annotation you will get your values mapped with the model you created in your system for handling any specific call. While by using @ResponseBody you can send anything back to the place from where the request was generated. Both things will be mapped easily without writing any custom parser etc.

What is the difference between @RequestBody and RequestParam? ›

So basically, while @RequestBody maps entire user request (even for POST) to a String variable, @RequestParam does so with one (or more - but it is more complicated) request param to your method argument.

What's the difference between @PathParam and @QueryParam RESTful annotations? ›

In a Java RESTful web service, the @QueryParam annotation is used to bind a query parameter to a method parameter, while the @PathParam annotation is used to bind a path parameter to a method parameter.

How many buttons should a controller have? ›

A Gamepad is narrowly defined as a device with two thumbsticks, a dpad, and four face buttons. Additionally, they will usually have two shoulder and two trigger buttons. Most gamepads also have two buttons in the middle section of the gamepad.

How do I know if my controller has drift? ›

The PS5 DualSense® controller comes with buttons and two analog sticks that help you play your favorite games. But if you're playing and the movement of your characters doesn't match what you're doing on the joystick, you may have controller drift.

How do I test all switch buttons? ›

Complete These Steps:

From the HOME Menu, select System Settings, then scroll down the menu on the left-hand side and select Controllers and Sensors. Select Test Input Devices, then Test Controller Buttons.

How to write unit test cases for controller in MVC? ›

Steps
  1. Add a new unit test project to the MVC module solution. ...
  2. Add the necessary MVC and DNN assembly references. ...
  3. (Optional) Use Moq to simulate a data store. ...
  4. Create the unit test. ...
  5. Retrofit the ItemController. ...
  6. Run the unit test.

Can we replace @controller with @RestController? ›

So if you are using latest spring version you can directly replace @Controller with @RestController without any issue.

Can we have more than one @rest controllers in Spring boot? ›

In Spring MVC, we can create multiple controllers at a time. It is required to map each controller class with @Controller annotation.

Why @controller is used in Spring? ›

The @Controller annotation indicates that a particular class serves the role of a controller. Spring does not require you to extend any controller base class or reference the Servlet API. However, you can still reference Servlet-specific features if you need to do so.

How do you write a unit test for a controller? ›

Unit tests of controller logic. Unit tests involve testing a part of an app in isolation from its infrastructure and dependencies. When unit testing controller logic, only the contents of a single action are tested, not the behavior of its dependencies or of the framework itself.

How to write JUnit test cases for Spring MVC controller using Mockito? ›

Now, we are gonna unit test one of the REST controller using Mockito.
  1. Introduction.
  2. Implementation. Add Dependencies. Create Utility Class. Test with Mock User. Using @WithMockUser Annotation. Using @WithUserDetails Annotation. Using Custom Annotation. ...
  3. Run JUnit Tests.
  4. References.
  5. Source Code.
  6. Conclusion.
Jul 7, 2021

How do you write a unit test case in spring? ›

The @Profile(“test”) annotation is used to configure the class when the Test cases are running. Now, you can write a Unit Test case for Order Service under the src/test/resources package. The complete code for build configuration file is given below.

How do you write integration test cases for controller in spring boot? ›

Testing in Spring Boot
  1. Overview. ...
  2. Project Setup. ...
  3. Maven Dependencies. ...
  4. Integration Testing With @SpringBootTest. ...
  5. Test Configuration With @TestConfiguration. ...
  6. Mocking With @MockBean. ...
  7. Integration Testing With @DataJpaTest. ...
  8. Unit Testing With @WebMvcTest.
Nov 27, 2022

Is it difficult to write unit test? ›

Developers experience Unit Testing as difficult when they run into these kinds of problems: Classes are tightly coupled to other classes, which makes it hard to test because you need to control those other classes as well when you are writing your tests. This is very, very difficult and very error prone.

Are unit tests hard to write? ›

But, being a white box software testing technique, unit testing is an in-depth process that requires a lot of knowledge about the code and how it interacts with other parts of the project. As a result, it can be hard to start writing unit tests, especially if you are new to the codebase.

How to write JUnit test cases for controller class in spring boot? ›

With the help of SpringJUnit4ClassRunner and MockMvc, we can create a web application context to write Unit Test for Rest Controller file. Unit Tests should be written under the src/test/java directory and classpath resources for writing a test should be placed under the src/test/resources directory.

How to write Mockito test cases for controller? ›

Try this. @RunWith(SpringJUnit4ClassRunner. class) @ContextConfiguration(locations = { "/META-INF/spring/applicationContext. xml"}) public class BulkRegistrationControllerTest { @Mock private RegistrationService registrationService; //Controller that is being tested.

Can we automate JUnit test cases? ›

Besides manual testing, JUnit is preferred equally for automation testing. It can also be used along with the Selenium WebDriver to automate tests for web applications. It provides a unique way to write structured, short, and better test cases.

Why use Mockito instead of JUnit? ›

Layman's Explanation with Example

JUnit is used to test APIs in source code. To test APIs in JUnit, sometimes we may require data classes. To create those, we can use mockito. Mock refers to creating duplicate or dummy objects.

Which annotation do you use @qualifier with? ›

The @Qualifier annotation can be used on any class annotated with @Component or on methods annotated with @Bean . This annotation can also be applied on constructor arguments or method parameters. Injecting Bike bean in VehicleService using @Autowired with @Qualifier annotation.

How do you write a unit test case manually? ›

However, every test case can be broken down into 8 basic steps.
  1. Step 1: Test Case ID. ...
  2. Step 2: Test Description. ...
  3. Step 3: Assumptions and Pre-Conditions. ...
  4. Step 4: Test Data. ...
  5. Step 5: Steps to be Executed. ...
  6. Step 6: Expected Result. ...
  7. Step 7: Actual Result and Post-Conditions. ...
  8. Step 8: Pass/Fail.
May 27, 2021

What is @SpringBootTest used for? ›

Spring Boot provides a number of utilities and annotations to help when testing your application. Test support is provided by two modules: spring-boot-test contains core items, and spring-boot-test-autoconfigure supports auto-configuration for tests.

What's the difference between unit test and integration test? ›

Unit Testing is a kind of white box testing, whereas Integration Testing is a kind of black-box testing. For Unit Testing, accessibility of code is required, as it tests the written code, while for Integration Testing, access to code is not required, since it tests the interactions and interfaces between modules.

Is SpringBootTest an integration test? ›

Spring Boot provides test slice configurations for narrow integration tests. To write broader integration tests, we can use the @SpringBootTest annotation. There are plenty of options to customize the application context in Spring Boot tests, but we should use them cautiously.

Videos

1. Spring Boot Testing Basics: How to Unit Test & Integration Test REST Controllers
(Dan Vega)
2. Setup MockMvc to Test Your Spring MVC @Controller and @RestController in Isolation
(rieckpil)
3. 009 spring mvc controller unit test
(Zheng Jun)
4. Using Spring MVC Test with Mockito and JUnit
(Spring Framework Guru)
5. Using Spring MVC Test to Unit Test a Thymeleaf Index Page
(Spring Framework Guru)
6. Unit Testing a MVC Controller (#5)
(SourceCodeAcademy)

References

Top Articles
Latest Posts
Article information

Author: Margart Wisoky

Last Updated: 07/31/2023

Views: 5991

Rating: 4.8 / 5 (78 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Margart Wisoky

Birthday: 1993-05-13

Address: 2113 Abernathy Knoll, New Tamerafurt, CT 66893-2169

Phone: +25815234346805

Job: Central Developer

Hobby: Machining, Pottery, Rafting, Cosplaying, Jogging, Taekwondo, Scouting

Introduction: My name is Margart Wisoky, I am a gorgeous, shiny, successful, beautiful, adventurous, excited, pleasant person who loves writing and wants to share my knowledge and understanding with you.