Testing Spring MVC with Spring Boot 1.4: Part 1
7 CommentsLast Updated on June 24, 2019 by Simanta
In my earlier Integration Testing with Spring and JUnit post, I discussed how to test a service bean facade with JUnit. I also posted a video, titled Testing Spring with JUnit on YouTube. In post, Spring Boot Web Application – Part 3 – Spring Data JPA, I showed how to test a Spring Data JPA repository of a Spring MVC application.
It has been more than a year now since I wrote these posts and posted the video. Since then, there’s been an exciting overhaul of testing support for Spring Boot MVC applications. The Spring Boot 1.4 release includes a number of exciting new testing features for our use.
In this post, I will look the new Spring MVC testing features. And I’ll show you how to put them to use.
Spring Boot 1.4 Testing Enhancements
In Spring Boot 1.3, there’s a lot of choices to write tests for a Spring MVC application. One option to set Spring MVC is shown in my earlier post here. In this post on Spring Boot 1.3, the @RunWith annotation with @ContextConfiguration is used to test for a business service façade, like this:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ProductServiceTestConfig.class})
public class ProductServiceImplIT {
private ProductService productService;
@Autowired
public void setProductService(ProductService productService) {
this.productService = productService;
}
@Test
public void testGetProduct(){
/*Test code*/
}
}
Another method I used in the post here is a combination of the @RunWith annotation with @SpringApplicationConfiguration to test a Spring Data JPA repository, like this:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {RepositoryConfiguration.class})
public class ProductRepositoryTest {
private ProductRepository productRepository;
@Autowired
public void setProductRepository(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Test
public void testSaveProduct(){
/*Test code*/
}
}There are several other approaches you can check in the official Spring blog here.
The testing approaches I used above are actually integration tests. A pure unit test shouldn’t create and load Spring Context.
Spring Boot 1.4 replaces these various testing approaches that via a single @SpringBootTest annotation for regular integration tests.
Prior to Spring Boot 1.4, I found Spring was lacking a simplified unit testing approach. This is really no surprise. The Spring team is always creating. Spring and Spring Boot offers a number of testing options. Due to innvotation, the testing options have evolved over time. In Spring Boot 1.4, the Spring committers took some time to clean testing up. They gave us much simpler options to use for testing Spring Boot applications. For example, a simple approach to unit test a controller having @Autowired external services without having to load Spring Context was lacking. With Spring Boot 1.4, it’s now possible.
Another missing piece that Spring Boot 1.4 tackels, is the ability to test portions (slices) of code. This can be done without the need to fire up a server. And with out the need to load up the entire Spring Context. Spring Boot 1.4 does this through the new Test Slicing feature that is designed to set-up a narrow slice of the Spring Context. This makes testing single ‘slices’ much easier. You can now focus on testing specific slices of your application. For example:
For example:
- MVC slice: Controller code through the
@WebMvcTestannotation - JPA slice: Spring Data JPA repository code through the
@DataJpaTestannotation - JSON slice: JSON serialization code through the
@JsonTestannotation
This may not seem like much at first glance. But when you have a large application starting the Spring context in testing, it is time consuming. Context loads can really increase your build time.
Let’s start putting the new test features to use.
The Application Under Test
I wrote a series of posts on Spring MVC starting off from Spring Boot Web Application – Part 1 – Spring Initializer. In the last post of the series, Spring Boot Web Application – Part 4 – Spring MVC, I completed creating a Spring MVC application to perform Create, Read, Update, and Delete (CRUD) operations.
In this post, I’ll show you how to write tests for the controllers of the same Spring MVC application.
If you are new to Spring MVC, you should go through my series on Spring MVC starting here.
You can also download the source code of the application available on GitHub here to follow along this post.
It’s a pretty simple example of a Spring Boot MVC application consisting of the following primary components:
Product: The domain object, which is a JPA entityIndexController: Returns theindex.htmlThymeleaf template for aGETrequest to the application rootProductController: Contains number of actions methods that useProductServiceto perform CRUD operations via the repository modelProductRepository: A Spring Data JPA repositoryProductService: A business service façade interfaceProductServiceImpl: A business service façade implementation annotated with@Service
With the Spring Boot MVC application that will be under test in place, lets start by writing few tests for the controllers.
Maven Dependencies
The testing features we’re looking at were introduced in Spring Boot 1.4. The version of Spring Boot we’ll be using is 1.4.0.RELEASE.
Here is the complete Maven POM that we’ll use.
pom.xml
4.0.0 guru.springframework springmvctest 0.0.1-SNAPSHOT jar springmvctest Examples of Spring MVC Test org.springframework.boot spring-boot-starter-parent 1.4.0.M3 UTF-8 1.8 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-web compile org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 org.webjars bootstrap 3.3.4 org.webjars jquery 2.1.4 org.springframework.boot spring-boot-maven-plugin spring-milestones http://repo.spring.io/milestone spring-milestones http://repo.spring.io/milestone
Unit Testing Spring MVC Controllers
MockMvc has been around since Spring 3.2. This providing a powerful way to mock Spring MVC for testing MVC web applications. Through MockMvc, you can send mock HTTP requests to a controller and test how the controller behaves without running the controller within a server. You can obtain a MockMvc instance through the following two methods of MockMvcBuilders:
standaloneSetup(): Registers one or more@Controllerinstances and allows programmatically configuring the Spring MVC infrastructure to build aMockMvcinstance. This is similar to plain unit tests while also making it possible to focus tests around a single controller at a time.webAppContextSetup(): Uses the fully initialized (refreshed)WebApplicationContextto build aMockMvcinstance. This lets Spring load your controllers as well as their dependencies for a full-blown integration test.
Pro Tip: Whenever possible, I will try to use standaloneSetup() for my SpringMVC tests. Your tests will remain true unit tests and stay blazing fast!
This is the IndexController that we are going to test:
IndexController.java
package guru.springframework.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/")
String index(){
return "index";
}
}
For our purpose, we’re starting with standaloneSetup() to test this IndexController.
The test class is this.
IndexControllerTest.java
package guru.springframework.controllers;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
@RunWith(SpringRunner.class)
public class IndexControllerTest {
private MockMvc mockMvc;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(new IndexController()).build();
}
@Test
public void testIndex() throws Exception{
this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andDo(print());
}
}
The test class above is a JUnit test. If you are new to JUnit, you should go through my series on unit testing with JUnit, starting from here. In the test class above, observe the new Spring Boot 1.4 test runner, named SpringRunner that we specified for @RunWith in Line 20. Under the hood, both SpringRunner and its predecessor SpringJUnit4ClassRunner are the same. SpringRunner is only the new name for SpringJUnit4ClassRunner – to just make it easy on the eyes.
In the @Before annotated method that runs before all @Test method, we programmatically constructed a MockMvc instance after registering the IndexController instance.
In the @Test method, we used the MockMvc instance to verify the following behavior of IndexController:
- HTTP status code
200is returned - The name of the returned view is
index
Finally, by using andDo(print()), we get the following output on the console
Testing the Spring MVC Slice
The unit test we wrote were for some basic expectations of the controller. Let’s write some more specific tests, this time to test ProductController. This time we’re going to use webAppContextSetup() to build MockMvc.
For a quick recap, the ProductController class is this.
ProductController.java
package guru.springframework.controllers;
import guru.springframework.domain.Product;
import guru.springframework.services.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class ProductController {
private ProductService productService;
@Autowired
public void setProductService(ProductService productService) {
this.productService = productService;
}
@RequestMapping(value = "/products", method = RequestMethod.GET)
public String list(Model model){
model.addAttribute("products", productService.listAllProducts());
return "products";
}
@RequestMapping("product/{id}")
public String showProduct(@PathVariable Integer id, Model model){
model.addAttribute("product", productService.getProductById(id));
return "productshow";
}
@RequestMapping("product/edit/{id}")
public String edit(@PathVariable Integer id, Model model){
model.addAttribute("product", productService.getProductById(id));
return "productform";
}
@RequestMapping("product/new")
public String newProduct(Model model){
model.addAttribute("product", new Product());
return "productform";
}
@RequestMapping(value = "product", method = RequestMethod.POST)
public String saveProduct(Product product){
productService.saveProduct(product);
return "redirect:/product/" + product.getId();
}
@RequestMapping("product/delete/{id}")
public String delete(@PathVariable Integer id){
productService.deleteProduct(id);
return "redirect:/products";
}
}
We will start by testing the behavior of ProductController.list() method. For a GET request to /product, we will perform the following verification:
- The
ProductServicemock is not null - The HTTP status code
200is returned - The returned content type is
text/html;charset=UTF-8 - The name of the returned view is
products - The view contains the
Spring Framework Gurustring
Here is the test class.
ProductControllerTest.java
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
public class ProductControllerTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@MockBean
private ProductService productServiceMock;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void testList() throws Exception {
assertThat(this.productServiceMock).isNotNull();
mockMvc.perform(MockMvcRequestBuilders.get("/products"))
.andExpect(status().isOk())
.andExpect(content().contentType("text/html;charset=UTF-8"))
.andExpect(view().name("products"))
.andExpect(MockMvcResultMatchers.view().name("products"))
.andExpect(content().string(Matchers.containsString("Spring Framework Guru")))
.andDo(print());
}
}
As we are testing the MVC slice of the application (testing whether the ProductController is working as expected), we used the @WebMvcTest annotation combined with @RunWith(SpringRunner.class).
As we planned to use webAppContextSetup() to build MockMvc, we @autowired WebApplicationContext in Line 6 – Line 7 to bring it into our test. Then in line 13, we passed WebApplicationContext as an argument to webAppContextSetup() to build the MockMvc instance.
Going back to the ProductController class under test, note that the controller class is @Autowired with ProductService. Therefore, we used the @MockBean annotation to define a Mockito mock for ProductService (Line 8 -Line 9) that will be passed to the controller. If you are new to mocking in unit tests, checkout my Mocking in Unit Tests with Mockito post.
Coming back to the test, in Line 17 we used the AssertJ library to assert that the ProductService mock is not null.
Note: Starting with Spring Boot 1.4, AssertJ comes out-of-the-box with Spring Boot to provide a fluent assertion API with a plan to replace JUnit’s org.junit.Assert class.
From Line 19 – Line 23, it’s all about verifying our expectations. As you can see, a lot of static methods are being used in this test method, including static methods of MockMvcRequestBuilders (get()), MockMvcResultMatchers (status(), content(), and view()), MockMvcResultMatchers (match()), and Hamcrest Matcher’s (match()). The last two match() are similar and performs the same functions in our test. They exist together only to demonstrate the different approaches that can be used.
Our test method reads naturally. First it performs a
First it performs a GET request against /products. Then it expects that the request is successful (isOk() asserts an HTTP 200 response code) and that the content type and name of the view is text/html;charset=UTF-8 and products respectively. Finally, it asserts that the view contains the Spring Framework Guru string.
When all the expectations pass, Line 24 prints the result out to the console.
The important thing to note here is that at no time is the application gets deployed to a server. The Tomcat container is not used. Instead the application runs within a mocked out Spring MVC to handle the HTTP request that we provided through the
Instead the application runs within a mocked out Spring MVC to handle the HTTP request that we provided through the MockMvc instance.
Here is the test result in the console.

The complete output of the test sent to console is this.
MockHttpServletRequest:
HTTP Method = GET
Request URI = /products
Parameters = {}
Headers = {}
Handler:
Type = guru.springframework.controllers.ProductController
Method = public java.lang.String guru.springframework.controllers.ProductController.list(org.springframework.ui.Model)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = products
View = null
Attribute = products
value = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/html;charset=UTF-8]}
Content type = text/html;charset=UTF-8
Body = <!DOCTYPE html>
<html>
<head lang="en">
<title>Spring Framework Guru</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="/webjars/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" media="screen" />
<script src="/webjars/jquery/2.1.4/jquery.min.js"></script>
<link href="/css/guru.css" rel="stylesheet" media="screen" />
</head>
<body>
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">Home</a>
<ul class="nav navbar-nav">
<li><a href="/products">Products</a></li>
<li><a href="/product/new">Create Product</a></li>
</ul>
</div>
</div>
</nav>
<div class="jumbotron">
<div class="row text-center">
<div class="">
<h2>Spring Framework Guru</h2>
<h3>Spring Boot Web App</h3>
</div>
</div>
<div class="row text-center">
<img src="/images/NewBannerBOOTS_2.png" width="400" />
</div>
</div>
</div>
</body>
</html>
Forwarded URL = null
Redirected URL = null
Cookies = []
Testing Spring MVC Slice with @Autowired MockMvc
Now let’s test the behavior of showProduct() of ProductController. Instead of manually building MockMvc, we’ll use a @Autowired MockMvc in the test and let Spring create, configure, and provide a MockMvc for us.
This is how the test class now looks minus any @Test method implementations.
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
@AutoConfigureMockMvc(secure=false)
public class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@MockBean
private ProductService productServiceMock;
Product product1;
@Before
public void setUpProduct() throws Exception{
product1 = new Product();
product1.setId(1);
product1.setProductId("235268845711068308");
product1.setDescription("Spring Framework Guru Shirt");
product1.setPrice(new BigDecimal("18.95"));
product1.setImageUrl("http://springframework.guru/wp-content/uploads/2015/04/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg");
}
@Test
public void testList() throws Exception {
/*Test code*/
}
@Test
public void testShowProduct() throws Exception {
/*Test code*/
}
}
In the test class above, notice that we used the @Autowired annotation on MockMvc in Line 5 – Line 6 instead of building it manually.
An @Autowired MockMvc combined with @WebMvcTest(controllers = ProductController.class) gives us a fully configured MockMvc instance with Spring security configured to set up BASIC authentication.
At this point, if we run the ProductControllerTest.testList() test again, we’ll encounter an authentication error, like this.
MockHttpServletResponse:
Status = 401
Error message = Full authentication is required to access this resource
We’re getting the 401 response because Spring Boot is auto-configuring Spring Security for us.
To disable the Spring Security auto-configuration, we can the MockMvc instance to disable security with @AutoConfigureMockMvc(secure=false) in Line 3.
Note, in the @Before method, we created and initialized a Product domain object that we will use in the @Test method.
The @Test method is this:
. . .
@Test
public void testShowProduct() throws Exception {
assertThat(this.productServiceMock).isNotNull();
when(productServiceMock.getProductById(1)).thenReturn(product1);
MvcResult result= mockMvc.perform(get("/product/{id}/", 1))
.andExpect(status().isOk())
.andExpect(view().name("productshow"))
.andExpect(MockMvcResultMatchers.model().attributeExists("product"))
.andExpect(model().attribute("product", hasProperty("id", is(1))))
.andExpect(model().attribute("product", hasProperty("productId", is("235268845711068308"))))
.andExpect(model().attribute("product", hasProperty("description", is("Spring Framework Guru Shirt"))))
.andExpect(model().attribute("product", hasProperty("price", is(new BigDecimal("18.95")))))
.andExpect(model().attribute("product", hasProperty("imageUrl", is("http://springframework.guru/wp-content/uploads/2015/04/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg"))))
.andReturn();
MockHttpServletResponse mockResponse=result.getResponse();
assertThat(mockResponse.getContentType()).isEqualTo("text/html;charset=UTF-8");
Collection<String> responseHeaders = mockResponse.getHeaderNames();
assertNotNull(responseHeaders);
assertEquals(1, responseHeaders.size());
assertEquals("Check for Content-Type header", "Content-Type", responseHeaders.iterator().next());
String responseAsString=mockResponse.getContentAsString();
assertTrue(responseAsString.contains("Spring Framework Guru"));
verify(productServiceMock, times(1)).getProductById(1);
verifyNoMoreInteractions(productServiceMock);
}
. . .In the @Test method above:
- Line 4: Performs an AssertJ assertion to test that the
ProductServicemock is notnull. - Line 5: Uses Mockito to stub the
getProductById()method on theProductServicemock to return the initializedProductinstance - Line 8 to Line 15: Performs the following verifications for a
GETrequest toproduct/{id}: - The HTTP status code
200is returned - The name of the returned view is
productshow - The view model contains a
productattribute - The various properties of the
productattribute matches against the values we used to initializeProduct
- The HTTP status code
- Line 16: Returns the result as
MvcResult - Line 19- Line 20: Uses AssertJ to assert that the content type of the response is
text/html;charset=UTF-8 - Line 22- Line 27: Uses JUnit assertions to assert that:
- The response header that
MvcResultreturns asMockHttpServletResponseis notnull - There is only one response header
- The response header name is
Content-Type - The response contains the
Spring Framework Gurustring
- The response header that
- Line 29 -Line 30: Uses Mockito to verify that the
getProductById()is called only once on theProductServicemock, and that no other methods of theProductServicemock are called during the test.
The complete test class is this:
ProductControllerTest.java
package guru.springframework.controllers;
import guru.springframework.domain.Product;
import guru.springframework.services.ProductService;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.math.BigDecimal;
import java.util.Collection;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.web.context.WebApplicationContext;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = ProductController.class)
@AutoConfigureMockMvc(secure=false)
public class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@MockBean
private ProductService productServiceMock;
Product product1;
@Before
public void setUpProduct() throws Exception{
product1 = new Product();
product1.setId(1);
product1.setProductId("235268845711068308");
product1.setDescription("Spring Framework Guru Shirt");
product1.setPrice(new BigDecimal("18.95"));
product1.setImageUrl("http://springframework.guru/wp-content/uploads/2015/04/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg");
}
@Test
public void testList() throws Exception {
assertThat(this.productServiceMock).isNotNull();
mockMvc.perform(MockMvcRequestBuilders.get("/products"))
.andExpect(status().isOk())
.andExpect(content().contentType("text/html;charset=UTF-8"))
.andExpect(view().name("products"))
.andExpect(MockMvcResultMatchers.view().name("products"))
.andExpect(content().string(Matchers.containsString("Spring Framework Guru")))
.andDo(print());
}
@Test
public void testShowProduct() throws Exception {
assertThat(this.productServiceMock).isNotNull();
when(productServiceMock.getProductById(1)).thenReturn(product1);
MvcResult result= mockMvc.perform(get("/product/{id}/", 1))
.andExpect(status().isOk())
.andExpect(view().name("productshow"))
.andExpect(MockMvcResultMatchers.model().attributeExists("product"))
.andExpect(model().attribute("product", hasProperty("id", is(1))))
.andExpect(model().attribute("product", hasProperty("productId", is("235268845711068308"))))
.andExpect(model().attribute("product", hasProperty("description", is("Spring Framework Guru Shirt"))))
.andExpect(model().attribute("product", hasProperty("price", is(new BigDecimal("18.95")))))
.andExpect(model().attribute("product", hasProperty("imageUrl", is("http://springframework.guru/wp-content/uploads/2015/04/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg"))))
.andReturn();
MockHttpServletResponse mockResponse=result.getResponse();
assertThat(mockResponse.getContentType()).isEqualTo("text/html;charset=UTF-8");
Collection responseHeaders = mockResponse.getHeaderNames();
assertNotNull(responseHeaders);
assertEquals(1, responseHeaders.size());
assertEquals("Check for Content-Type header", "Content-Type", responseHeaders.iterator().next());
String responseAsString=mockResponse.getContentAsString();
assertTrue(responseAsString.contains("Spring Framework Guru"));
verify(productServiceMock, times(1)).getProductById(1);
verifyNoMoreInteractions(productServiceMock);
}
}
The complete output of the test sent to console is this:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /product/1/
Parameters = {}
Headers = {}
Handler:
Type = guru.springframework.controllers.ProductController
Method = public java.lang.String guru.springframework.controllers.ProductController.showProduct(java.lang.Integer,org.springframework.ui.Model)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = productshow
View = null
Attribute = product
value = guru.springframework.domain.Product@6069dd38
errors = []
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/html;charset=UTF-8]}
Content type = text/html;charset=UTF-8
Body = <!DOCTYPE html>
<html>
<head lang="en">
<title>Spring Framework Guru</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="/webjars/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" media="screen" />
<script src="/webjars/jquery/2.1.4/jquery.min.js"></script>
<link href="/css/guru.css" rel="stylesheet" media="screen" />
</head>
<body>
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">Home</a>
<ul class="nav navbar-nav">
<li><a href="/products">Products</a></li>
<li><a href="/product/new">Create Product</a></li>
</ul>
</div>
</div>
</nav>
<div class="jumbotron">
<div class="row text-center">
<div class="">
<h2>Spring Framework Guru</h2>
<h3>Spring Boot Web App</h3>
</div>
</div>
<div class="row text-center">
<img src="/images/NewBannerBOOTS_2.png" width="400" />
</div>
</div>
<h2>Product Details</h2>
<div>
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Product Id:</label>
<div class="col-sm-10">
<p class="form-control-static">1</p></div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<p class="form-control-static">Spring Framework Guru Shirt</p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Price:</label>
<div class="col-sm-10">
<p class="form-control-static">18.95</p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Image Url:</label>
<div class="col-sm-10">
<p class="form-control-static">http://springframework.guru/wp-content/uploads/2015/04/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg</p>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
Forwarded URL = null
Redirected URL = null
Cookies = []
Summary
The new @WebMVC used with MockBean allows creating powerful yet simple tests for your Spring MVC apps. Unlike the @SpringBootTest annotation, the @WebMvcTest annotation disables full auto-configuration. @WebMvcTest only auto-configures the Spring MVC infrastructure and limits scanned beans to @Controller, @ControllerAdvice, @JsonComponent, Filter, WebMvcConfigurer, and HandlerMethodArgumentResolver beans.
When you use @WebMvcTest, regular @Component, @Service, or @Repository beans will not be scanned – an important point to differentiate @WebMvcTest from a full-blown @SpringBootTest.
If you’re looking to load your full application configuration and use MockMVC, you should consider @SpringBootTest combined with @AutoConfigureMockMvc rather than @WebMvcTest. I will cover it in an upcoming post of this Spring MVC testing series. I will also help you to explore more about mocking services and JPA repositories with @MockBean combined with @DataJpaTest and @WebMvcTest, and also how to unit test RESTful controller’s GETs and POSTs using MockMvc and @JsonTest.


dvega
Really great article John! Looking forward to the next installment of this series 🙂
jt
Thanks Dan!
Mario Kusek
Nice post. Thanks!
What I have trouble testing is controller method that has argument UserDetails. I always get null value. Can you write post about that?
RizziCR
Nice Article.
The Link for “Spring Boot Web Application – Part 3 – Spring Data JPA” at the first paragraph is not working/linked to “about:blank”
mohdalihpk
It is great article. I never think spring boot like this. Can you write an article on spring boot application split in multiple jars? Let me explain, I am using entities in two applications but the entities are exactly same, how can I make a jar and distribute in both projects. The jars also use spring capabilities.
Looking forward for your reply.
jt
Glad you liked it. I don’t have an example handy – but what you’re asking about is a multi-module project – which is easy to do in Maven or Gradle.