Spring Boot – REST Integration Tests with Maven

Think about having a little REST-Application that contains some type of data, for example handling some User. You now want to know what exactly happens on every application level, when your REST-API is called. And, of course, you want to find bugs.

If you don´t have time for reading all the content of the post, the entire Test class is expandable at the end of this one.

Pre Conditions

My example application is using h2 database and JPA (repositories) for storing the data. If you use an other way for handling your data feel free to use it. It shouldn´t have a big impact in our test implementation. For serialization and deserialization to/from JSON I´m using jackson. 

If you haven´t already an application please visit this little beauty.

Maven Dependency

As mentionend in the title of this post, we´re working with Maven so we need the dependency for the test.

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
</dependency>
<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-test</artifactId>
     <scope>test</scope>
</dependency>

Implementation

Now, after we finished with the Pre Conditions, we start with our implementation of the test(s).

Basic Test Class

Now, after we finished with the Pre Conditions, we start with our test class.

import com.javadevcorner.profilingExample.AppStarter;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

/**
 *
 * @author javadevcorner.com
 */
@RunWith( SpringJUnit4ClassRunner.class )
@SpringBootTest( classes = { AppStarter.class } )
@WebAppConfiguration
public class UserResourceIntegrationTest {

 
   //code will come up early

}

The first annotation provides us some functionalities of the Spring Test Context Framework.
Because we´ll implement a integration test, we need to create the Spring Boot Context by @SpringBootTest. The classes in brackets is your startup class of your Spring Boot Application (the class where your main method is located).
The third annotation tells our Testclass, that we want to test a Web Application so we need the Annotation @WebAppConfiguration.

Class Parameters

Now, before we start with the first test, we need some global parameters. Because we are working in the Spring Boot Context (provided by our Annotation), we can autowire some components we need.

import org.springframework.web.context.WebApplicationContext;
import com.javadevcorner.profilingExample.user.persistence.UserRepository;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.beans.factory.annotation.Autowired;

    //..... class and import things....

    @Autowired
    WebApplicationContext applicationContext;

    @Autowired
    UserRepository userRepository;
    
    MockMvc mockMvc;

    //..... test methods....


Test GET Method

So let´s begin testing our HTTP-GET method.

import com.fasterxml.jackson.databind.ObjectMapper;
import com.javadevcorner.profilingExample.user.persistence.User;
import java.util.Arrays;
import java.util.List;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


//....class things and imports ....

@Test
public void testGetAllUser() throws Exception {
        
        List<User> allUser = new UserIntegrationMockDataSetup().getAllUser();
        
        userRepository.saveAll(allUser);
        
        mockMvc = MockMvcBuilders
                    .webAppContextSetup(applicationContext)
                    .build();
        
        MvcResult mvcResult 
                = mockMvc.perform(get("/api/allUser"))
                    .andExpect(status().isOk())
                    .andReturn();
        
        User[] actualUsers 
                = new ObjectMapper()
                        .readValue(mvcResult.getResponse()
                                .getContentAsString()
                                    , User[].class);
        
        assertThat( allUser, Matchers.is(Arrays.asList(actualUsers)) );
}    

//....other test methods ....

Okai, huh, a lot of code. Isn´t it?! But don´t worry we´ll go through it.

Of course, we must fill up our database with users. That´s what we do in the first two lines of the method

The MockMvcBuilders is setting up the WebApplicationContext as we need it (based on the Startup of our application)

MvcResult is performing a REST call against our User API. It uses the connection String (in my example api/allUser). We are expecting the http statuscode 200 and a return value.

The ObjectMapper() of fasterxml.jackson is been used to map the result of MvcResult to a JSON and subsequently to an Array of type User. 

The last step is just a comparison of the entries ini the original allUser List and the returned User Array.
That´s it. Not that hard isn´t it? Just a lot to know about what objects we need but Spring Boot supports a lot on here.

Test POST Method

The POST Method is quite similar to the GET.

@Test  
public void testCreateUser() throws Exception {
    
    userRepository.deleteAll();

    mockMvc = MockMvcBuilders
            .webAppContextSetup(applicationContext)
            .build();

    User user = User
            .builder()
            .id(1)
            .username("FirstOne")
            .password("PlainPasswordLOL")
            .build();

    String requestBody
            = new ObjectMapper()
                    .writeValueAsString(user);

    mockMvc
            .perform(post("/api/createUser")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(requestBody))
            .andExpect(status().isOk());
    
    assertEquals(1, userRepository.findAll().size());

}

Watch the mockMvc.perform(…. part. We now perform a post and add content to this post call. Furthermore we define what type of content (JSON) we send to our API and, as already seen in the GET test, we expect a specfic status. But we are not expecting a response.
So we need to check our repository (which we cleared at the beginnig of the test) if there´s exactly one entry in the database.

Tests for PUT and DELETE are treated nearly the same, so feel free to try them out. 

Run the test with Maven

Running the integration test with Maven can be achieved by the following command.

mvn clean test-compile test

But of course, feel free to start the tests how ever you want.

Watch out for the imports. Sometimes your test will fail cause of a wrong import

Entire Test Class

Feel free to share

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.