Spring Boot Test: Writing Unit Tests for the Controller Layers with @WebMvcTest

 

Unit Tests and Integration Tests

@SpringBootTest annotation will load the fully ApplicationContext. Therefore it is highly used for writing the integration testing in web server environment. This will not use slicing and scan for all the stereotype annotations (@Component@Service, @Respository and @Controller / @RestController) and loads the full application context. Therefore this is more good at in the context of writing integration testing for the application.

@WebMvcTest annotation will load only the controller layer of the application. This will scan only the @Controller/ @RestController annotation and will not load the fully ApplicationContext. If there is any dependency in the controller layer (has some dependency to other beans from your service layer), you need to provide them manually by mocking those objects.

Therefore @SpringBootTest is widely used for Integration Testing purpose and @WebMvcTest is used for controller layer Unit testing.

 

@WebMvcTest

As already described above, @WebMvcTest annotation can be used to test the controller slice of the application. This annotation is going to scan only the controllers (including RestControllers) you’ve defined and the MVC infrastructure. That’s it. So if your controller has some dependency to other beans from your service layer, the test won’t start until you either load that config yourself or provide a mock for it. This is much faster as we only load a tiny portion of your app and good for writing the Unit Tests for the Controller layer.

 

@WebMvcTest will :

  • Auto-configure Spring MVC, Jackson, Gson, Message converters etc.
  • Load relevant components (@Controller@RestController@JsonComponent etc)
  • Configure MockMVC

 

@WebMvcTest is limited (bound) to a single controller and is used in combination with @MockBean to provide mock implementations for required collaborators.

e.g:-  @WebMvcTest(UserController.class) 

As you can see that above @WebMvcTest annotation is bound to the UserController.

 

MockMvc

@WebMvcTest also auto-configures MockMvcMockMVC offers a powerful way to quickly test MVC controllers without needing to start a full HTTP server.

 

No Web Server is Started with @WebMvcTest

@WebMvcTest does not start any server. Since the web server is not started,  RestTemplate or TestRestTemplate cannot be used with @WebMvcTest environment.

If you want to use RestTemplate or TestRestTemplate, then you need to start a server with @SpringBootTest (using webEnviroment attribute).

 

 

Integrating Spring Security with MockMvc

Since WebMvcTest is only sliced controller layer for the testing, it would not take the security configurations. Therefore the main Spring Security Configuration class should be imported to your Test Class.

@Import(SpringSecurityConfig.class)

After adding the above import statement for the Test class, the Spring Security context will be accessible for all the test cases under that test class. Therefore the test cases can send authenticated requests to access the secured REST endpoints (that are secured with Spring Security). If you look at  the UserControllerWebMvcTest, you can see that main Spring Security Configuration class is imported (please refer the below code segment).

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@Import(SpringSecurityConfig.class)
public class UserControllerWebMvcTest {

 

 

UserControllerWebMvcTest.java

 

For the demonstration purpose of this article, i will extract few important points from UserControllerWebMvcTest class. If you want to look at the full source code, please download it from GitHub. (Please refer the source code section of this article)

 

 

Here are some important things to note ….

 

Mockito.when(userService.create(ArgumentMatchers.any(AddUserRequest.class))).thenReturn(addUserResponse);

Here the ‘UserService.create’ method is mocked to return ‘addUserResponse‘ object.  the method can accept any object which is type is ‘AddUserRequest.class‘.

 

addUserRequest‘ is used as the request body of the  POST  /users REST Api invocation.

 

httpBasic(username, password) :- for HTTP basic authentication.

 

MvcResult will hold the return response after executing the Test case.

 String jsonResponse = mvcResult.getResponse().getContentAsString();
 AddUserResponse userCreated = new ObjectMapper().readValue(jsonResponse, AddUserResponse.class);

Converting the response body stored in the  MvcResult object into the type of AddUserResponse.class.

 

 

Source Code

The full source code of this article can be found at GitHub. Click here to download it.  For displaying the code coverage analysis, i have used the JaCoco with SonarQube.

If you want to refresh your knowledge on JaCoco with SonarQube, please click here to refer my article on that. 

 

Code Coverage Analysis with JaCoco and SonarQube

You can run the test cases and generate the JaCoco code coverage analysis report with SonarQube with following command.

mvn test sonar:sonar -Dsonar.login=admin -Dsonar.password=admin

(Please change the login credentials according to your SonarQube server)

 

After executing the above command successfully, you can access the code coverage analysis report with your web browser. (For the URL pattern, please refer the article about JaCoCo and SonarQube). It should show you the following report.

Screen Shot 2018-05-16 at 9.02.36 PM.png

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s