API Testing by Spring MVC Test Framework
by
What is API Testing
API testing is a type of software testing that invovles testing application programming interfaces (APIs) directly and as part of integration testing to determine if they meet expectations for functionality, reliability, performance, and security. Since APIs lack a GUI, API testing is performed at the message layer. API testing is now considered ciritcal for autmating testing because APIs now serve as the primary interface to application logic and because GUI tests are difficult to maintain with the short release cycles and frequent changes commonly used with Agile software development and DevOps.
https://en.wikipedia.org/wiki/API_testing
What is RESTful
Representational state transfer (REST) is a software architectural style that defines a set of constraints to be used for creating Web Services. Web services that conform to the REST architectural style, called RESTful Web services allow the requesting systems to access and manipulate textual representations of Web resources by using a uniform and predefined set of stateless oerations. Other kinds of Web services, such as SOAP Web services, expose their own arbitrary sets of operations.
"Web resources" were first defined on the World Wid Web as documents or files identified by their URLs. However, today they have a much more generic and abstract definition that encompasses every thing, entity, or action that can be identified, named, addressed, handled, or performed, in any way whatsoever, on the Web. In a RESTful Web service, requests made to a resource’s URI will elicit a response with a payload formatted in HTML, XML, JSON, or some other format. The response can confirm that some alteration has been made to the resource state, and the response can provide hypertext links to other related resources. When HTTP is used, as is most common, the operations (HTTP methods) available are GET, HEAD, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS and TRACE.
By using a stateless protocol and standard operations, RESTful systems aim for fast performance, reliability, and the ability to grow by reusing components that can be managed and updated without affecting the system as a whole, even while it is running.
https://en.wikipedia.org/wiki/Representational_state_transfer
Spring MVC Application
Spring MVC is the most popular framework to build RESTful Web services in Java world, at least till now.
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC", comes from the name of its source module (
spring-webmvc
), but it is more commonly known as "Spring MVC".
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#spring-web
The core of Spring MVC is DispatcherServlet
. DispatcherServlet
is an implementation of HttpServlet
, which intercept all incoming request and dispatch to controller. As it is a Servlet, DispatcherServlet
is running inside a Servlet Container. Servlet container handles HTTP communication, listen on port, receive request package and convert to HttpServletRequest
object, convert HttpServletResponse
object which return by controller (actually it is rendered by View) and send to client application.
The URI to controller method mappings are declared by annotations. For example,
@RestController
@RequestMapping("products")
public class ProductController {
...
@PostMapping
public Product create(@RequestBody Product entity) {
...
}
@PutMapping("{id}")
public Product update(@PathVariable("id") String id, @RequestBody Product entity) {
...
}
@DeleteMapping("{id}")
public void delete(@PathVariable("id") String id) {
...
}
@GetMapping("{id}")
public void getOne(@PathVariable("id") String id) {
...
}
...
}
It declares CRUD RESTful API against resource Product
:
URI Pattern | HTTP Method | Description |
---|---|---|
/products |
POST |
create new product entity |
/products/{id} |
PUT |
update the existed product which with id |
/products/{id} |
DELETE |
delete the existed product which with id |
/products/{id} |
GET |
get the existed product which with id |
Spring MVC Test Framework
The Spring MVC Test framework provides first class support for testing Spring MVC code with a fluent API that you can use with JUnit, TestNG, or any other testing framework. It is built on the Servlet API mock objects from the spring-test module and, hence, does not use a running Servlet container. It uses the DispatcherServlet to provide full Spring MVC runtime behavior and provides support for loading actual Spring configuration with the TestContext framework in addition to a standalone mode, in which you can manually instantiate controllers and test them one at a time.
Spring Boot scan and assemble MockMvc, controllers, DispatcherServlet and other beans. MockMvc is invoking doService
of DispatcherServlet for mocking HTTP request processing directly. Test case is able to perform request on DispatcherServelt through MockMvc.
Configure Spring MVC Test
Auto-Configuration is the remakrable feature offered by Spring Boot. Unexpectedly, Spring MVC Test framework offers auto-configuration of MockMvc. Annotation @AutoConfigureMockMvc
enable MockMvc auto configuration.
@ActiveProfiles({"test"})
@RunWith(SpringRunner.class) (1)
@SpringBootTest(classes = CatalogApplication.class) (2)
@AutoConfigureMockMvc (3)
public class ProductTest {
private static final String ENDPOINT = "/products";
@Autowired
private MockMvc mvc; (4)
@Autowired
private ObjectMapper objectMapper;
...
1 | run JUnit test case by SpringRunner which handle Spring context initialization, includes annotations scanning and bean assembling. |
2 | set root context for test case. |
3 | enable MockMvc auto-configuration. |
4 | inject MockMvc bean. |
Performing Requests
It can perform requests that use any HTTP method through MockMvc. For example:
mockMvc.perform(post("/products")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonContent));
MockMvc offers methods to specify each part of HTTP request.
A well formed HTTP request consists of three parts:
HTTP-message = start-line
*( header-field CRLF )
CRLF
[ message-body ]
start-line = request-line / status-line
request-line = method SP request-target SP HTTP-version CRLF
HTTP protocol defines nine methods, but only seven of them are defined for application:
-
GET
-
POST
-
PUT
-
DELETE
-
PATCH
-
OPTIONS
-
HEAD
It offers builder methods in MockMvcRequestBuilders
to contruct corresponding MockMvcRequestBuilder
. Application developer can specify each part of HTTP request through MockMvcRequestBuilder
.
Specify headers:
mockMvc.perform(post("/products")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.header("Custom-Header", "some value"));
Specify request body:
mockMvc.perform(post("/products")
.content(jsonContent));
Verify Responses
MockMvc wrapper response as ResultActions
. Application developer can verify each part of response through ResultActions
.
HTTP response message consists of three parts:
HTTP-message = start-line
*( header-field CRLF )
CRLF
[ message-body ]
start-line = request-line / status-line
status-line = HTTP-version SP status-code SP reason-phrase CRLF
It offers tools to extract information from response, and verify them.
Verify status code:
mockMvc.perform(post("/products")
.content(jsonContent))
.andExpect(status().isCreated());
Verify response body:
mockMvc.perform(post("/products")
.content(jsonContent))
.andExpect(jsonPath("$.title", is(title));