Testing Spring MVC With Spring Boot 1.4: Part I
If you’re looking to load your full app configuration and use MockMVC, you should consider @SpringBootTest combined with @AutoConfigureMockMvc rather than @WebMvcTest.
Join the DZone community and get the full member experience.
Join For FreeThere’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 that 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 innovation, 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 testing 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 tackles is the ability to test portions (slices) of code. This can be done without the need to fire up a server. Without the need to load up the entire Spring Context. Spring Boot 1.4 does this through the new Test Slicing feature, which 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:
- MVC slice.: Controller code through the @WebMvcTest annotation.
- JPA slice.: Spring Data JPA repository code through the @DataJpaTest annotation.
- JSON slice.: JSON serialization code through the @JsonTest annotation.
This may not seem like much at first glance. However, 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 with 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 with 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 entity.
- IndexController. Returns the index.html Thymeleaf template for a GET request to the application root.
- ProductController. Contains number of actions methods that use ProductService to perform CRUD operations via the repository model.
- ProductRepository. A Spring Data JPA repository.
- ProductService. A business service façade interface.
- ProductServiceImpl. 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:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>guru.springframework</groupId>
<artifactId>springmvctest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springmvctest</name>
<description>Examples of Spring MVC Test</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.M3</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
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 @Controller instances and allows programmatically configuring the Spring MVC infrastructure to build a MockMvc instance. 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) WebApplicationContext to build a MockMvc instance. This lets Spring load your controllers as well as their dependencies for a full-blown integration test.
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 purposes, 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 200 is 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 ProductService mock is not null.
- The HTTP status code 200 is 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 Guru string.
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.
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 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.
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("https://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 to 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 isrequired toaccess thisresource
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 that 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("https://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 ProductService mock is not null.
- Line 5: Uses Mockito to stub the getProductById() method on the ProductService mock to return the initialized Product instance
- Line 8 to Line 15: Performs the following verifications for a GET request to product/{id}:
- The HTTP status code 200 is returned.
- The name of the returned view is productshow.
- The view model contains a product attribute.
- The various properties of the product attribute matches against the values we used to initialize the product.
- Line 16: Returns the result as MvcResult.
- Line 19 to Line 20: Uses AssertJ to assert that the content type of the response is
text/html;charset=UTF-8. - Line 22 to Line 27: Uses JUnit assertions to assert that:
- The response header that MvcResult returns as MockHttpServletResponse is not null.
- There is only one response header.
- The response header name is Content-Type.
- The response contains the Spring Framework Guru string.
- Line 29 to Line 30: Uses Mockito to verify that the getProductById() is called only once on the ProductService mock, and that no other methods of the ProductService mock 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("https://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("https://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);
}
}
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.
Published at DZone with permission of John Thompson, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments