The previous part of my new Spring MVC Test tutorial taught us how we can configure the system under test when we are writing unit tests for "normal" Spring MVC controllers. We also learned that if we don't want to add duplicate code to our test classes, we should send HTTP requests to the system under test by using request builder classes. However, before we can implement the request builder methods which create and send HTTP requests to the system under test, we have to understand:
- How we can send HTTP requests by using the
MockMvc
class. - How we can write assertions for the returned HTTP response.
Unfortunately, this topic is so big that it cannot be covered in one blog post. That's why this blog post provides a very quick introduction to this topic, and the next parts of this tutorial provide "proper" answers to these questions.
Let's begin.
The Basic Structure of an Automated Test
When we want to write an automated test for a Spring MVC controller, we have to follow these steps:
- Create a
RequestBuilder
object which specifies what kind of an HTTP request is send to the system under test. - Send an HTTP request to the system under test by invoking the
perform()
method of theMockMvc
class, and pass the createdRequestBuilder
object as a method parameter. - Write assertions for the returned HTTP response by using the
ResultActions
object that's returned by theperform()
method of theMockMvc
class. We can write an assertion for the returned HTTP response by invoking theandExpect()
method of theResultActions
interface. When we invoke this method, we have to create a newResultMatcher
object and pass this object as a method parameter.
The pseudo code of our automated test looks as follows:
mockMvc.perform( //Specify what kind of an HTTP request is send to the system under test ) .andExpect( //Write an assertion for the returned HTTP response )
andExpect()
method of the ResultActions
interface returns a ResultActions
object, we can (and we should) perform multiple assertions by simply invoking the andExpect()
method multiple times. We will talk more about writing assertions in an upcoming part of this tutorial.Next, we will learn how we can specify what kind of an HTTP request is send to the system under test.
Specifying the HTTP request That's Send to the System Under Test
When we want to specify the HTTP request that's send to the system under test, we have to invoke a static factory method of the MockMvcRequestBuilders
class. This class provides factory methods which allow us to send GET
, POST
, PUT
, PATCH
, DELETE
, OPTIONS
, and HEAD
requests to the system under test. All factory methods return a MockHttpServletRequestBuilder
object that can be passed to the the perform()
method of the MockMvc
class as a method parameter.
When we invoke a factory method that creates a new MockHttpServletRequestBuilder
object, we have to pass two method parameters to the invoked method. These method parameters are:
- A URI template which uses the format that's supported by the
UriComponentsBuilder
class. - Zero or more URI variable values. These values are used to replace the variables found from the URI template by using the FIFO (first in, first out) principle.
Let's take a look at two examples which demonstrate how we can use the factory methods of the MockMvcRequestBuilders
class.
Example 1:
If we want to send a GET
request to the path: '/api/task/1', we have to invoke the get()
method of the MockMvcRequestBuilders
class. After we have invoked this method, the pseudo code of our automated test looks as follows:
mockMvc.perform(get("/api/task/{id}", 1L)) .andExpect( //Write an assertion for the returned HTTP response )
Example 2:
If we want to send a PUT request to the path: '/api/user/99/task/1', we have to invoke the put()
method of the MockMvcRequestBuilders
class. After we have invoked this method, the pseudo code of our automated test looks as follows:
mockMvc.perform(put("/api/user/{userId}/task/{taskId}", 99L, 1L)) .andExpect( //Write an assertion for the returned HTTP response )
- We could also use a hard coded URI string instead of a URI template. For example, we could replace '/api/task/{id}' with '/api/task/1'. However, this doesn't make sense if we are using a request builder class because the odds are that it has to send HTTP requests to different URIs.
- When we invoke a factory method that creates a new
MockHttpServletRequestBuilder
object, we could also create aURI
object and pass that object as a method parameter. I don't personally use this approach because I think that passing a URI template and variable values as method parameters makes my code easier to read. - The
MockHttpServletRequestBuilder
class has a very versatile API which allows us to build the HTTP request that's send to the system under test. We will take a closer look at this API in the next part of this tutorial.
Additional Reading:
We can now describe the structure of an automated test which uses the Spring MVC Test framework, and we can send a simple HTTP request to the system under test. Let's summarize what we learned from this blog post.
Summary
This blog post has taught us three things:
- We can send an HTTP request to the system under test by invoking the
perform()
method of theMockMvc
class. - We can create a new a
MockHttpServletRequestBuilder
object, which allows us to build the HTTP request that's send to the system under test, by using the static factory methods of theMockMvcRequestBuilders
class. - When we specify the Request-URI, we should use the syntax that's supported by the
UriComponentsBuilder
class.