This tutorial explains how to write the integration testing REST API in Spring Boot. This tutorial uses the examples written in the previous tutorial. This tutorial intends to create the automated testing using JUnit and runs with Spring Boot application.
This tutorial assumes the reader has enough already knowledge on the Spring REST web services. If you want to learn basic details of Spring We Services, please read our Introduction to Spring Web Services.
Automation testing is the most efficient way of doing the testing and save the cost for company by reducing the man power. This tutorial on how to write the integration testing REST API in Spring Boot application, would definitely help you to convert your existing REST projects into fully integrated testing environment.
Are you looking for more tutorials on Spring Framework :: Visit our Best Spring Tutorials
I wrote about building RESTful applications and also tested the same using Postman RESTful Client. But in an ideal scenario I would have to automate the testing of these RESTful APIs. In this post I am going to show you how exactly to do the integration testing for REST API using Spring Boot. I have written the complete code in my Github, you can access it for more details about the implementation.
Integration Testing REST API in Spring Boot
Firstly we need to add appropriate dependencies in the pom.xml for testing which is given below:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
JUnit Integration Testing Class for REST API
We are going to write the test classes using the JUnit library. Once we have completed the test class, we have to run this class from our environment. It can be done easily from the IDEs like Eclipse which supports JUnit execution as built-in functionality. Lets annotate the Controller test class as shown below:
package app.controller; import org.junit.runner.RunWith; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.WebIntegrationTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import app.Application; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebIntegrationTest public class BookControllerTest { //Required to Generate JSON content from Java objects public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); //Required to delete the data added for tests. //Directly invoke the APIs interacting with the DB @Autowired private BookRepository bookRepository; //Test RestTemplate to invoke the APIs. private RestTemplate restTemplate = new TestRestTemplate(); }
In the above code:
- SpringJUnit4ClassRunner is a custom extension of JUnit’s BlockJUnit4ClassRunner which provides functionality of the Spring TestContext Framework.
- @SpringApplicationConfiguration is a Class-level annotation that is used to determine how to load and configure an ApplicationContext for integration tests. We provide it with the configuration class which in this case is
Application
class. - @WebIntegrationTest Test class annotation signifying that the tests are “web integration tests” and therefore require full startup in the same way as a production application.
Also we need to specify the port at which the test server would run, among other approaches I prefer to create a application.properties
file in the src/test/resources directory. The contents of that file is given below:
server.port = 8888
With the above setup lets now individually test the APIs.
Testing the Create Book API
As given in the API design for Creating Book here, we need to pass the JSON of following format in Request body:
{ "name" : "Book 3", "isbn": "45567", "author" : "Author 3", "pages" : 200 }
Below is the code for testing the Create API:
@Test public void testCreateBookApi() throws JsonProcessingException{ //Building the Request body data Map<String, Object> requestBody = new HashMap<String, Object>(); requestBody.put("name", "Book 1"); requestBody.put("isbn", "QWER1234"); requestBody.put("author", "Author 1"); requestBody.put("pages", 200); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); //Creating http entity object with request body and headers HttpEntity<String> httpEntity = new HttpEntity<String>(OBJECT_MAPPER.writeValueAsString(requestBody), requestHeaders); //Invoking the API Map<String, Object> apiResponse = restTemplate.postForObject("http://localhost:8888/book", httpEntity, Map.class, Collections.EMPTY_MAP); assertNotNull(apiResponse); //Asserting the response of the API. String message = apiResponse.get("message").toString(); assertEquals("Book created successfully", message); String bookId = ((Map<String, Object>)apiResponse.get("book")).get("id").toString(); assertNotNull(bookId); //Fetching the Book details directly from the DB to verify the API succeeded Book bookFromDb = bookRepository.findOne(bookId); assertEquals("Book 1", bookFromDb.getName()); assertEquals("QWER1234", bookFromDb.getIsbn()); assertEquals("Author 1", bookFromDb.getAuthor()); assertTrue(200 == bookFromDb.getPages()); //Delete the data added for testing bookRepository.delete(bookId); }
Testing the Get Book Details API
Now lets test the API that is used to fetch the details of the Book.
@Test public void testGetBookDetailsApi(){ //Create a new book using the BookRepository API Book book = new Book("Book1", "ÏSBN1", "Author1", 200); bookRepository.save(book); String bookId = book.getId(); //Now make a call to the API to get details of the book Book apiResponse = restTemplate.getForObject("http://localhost:8888/book/"+ bookId, Book.class); //Verify that the data from the API and data saved in the DB are same assertNotNull(apiResponse); assertEquals(book.getName(), apiResponse.getName()); assertEquals(book.getId(), apiResponse.getId()); assertEquals(book.getIsbn(), apiResponse.getIsbn()); assertEquals(book.getAuthor(), apiResponse.getAuthor()); assertTrue(book.getPages() == apiResponse.getPages()); //Delete the Test data created bookRepository.delete(bookId); }
Testing the Update Book API
@Test public void testUpdateBookDetails() throws JsonProcessingException{ //Create a new book using the BookRepository API Book book = new Book("Book1", "ISBN1", "Author1", 200); bookRepository.save(book); String bookId = book.getId(); //Now create Request body with the updated Book Data. Map<String, Object> requestBody = new HashMap<String, Object>(); requestBody.put("name", "Book2"); requestBody.put("isbn", "ISBN2"); requestBody.put("author", "Author2"); requestBody.put("pages", 200); HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setContentType(MediaType.APPLICATION_JSON); //Creating http entity object with request body and headers HttpEntity<String> httpEntity = new HttpEntity<String>(OBJECT_MAPPER.writeValueAsString(requestBody), requestHeaders); //Invoking the API Map<String, Object> apiResponse = (Map)restTemplate.exchange("http://localhost:8888/book/" + bookId, HttpMethod.PUT, httpEntity, Map.class, Collections.EMPTY_MAP).getBody(); assertNotNull(apiResponse); assertTrue(!apiResponse.isEmpty()); //Asserting the response of the API. String message = apiResponse.get("message").toString(); assertEquals("Book Updated successfully", message); //Fetching the Book details directly from the DB to verify the API succeeded in updating the book details Book bookFromDb = bookRepository.findOne(bookId); assertEquals(requestBody.get("name"), bookFromDb.getName()); assertEquals(requestBody.get("isbn"), bookFromDb.getIsbn()); assertEquals(requestBody.get("author"), bookFromDb.getAuthor()); assertTrue(Integer.parseInt(requestBody.get("pages").toString()) == bookFromDb.getPages()); //Delete the data added for testing bookRepository.delete(bookId); }
Testing the Delete Book API
@Test public void testDeleteBookApi(){ //Create a new book using the BookRepository API Book book = new Book("Book1", "ISBN1", "Author1", 200); bookRepository.save(book); String bookId = book.getId(); //Now Invoke the API to delete the book restTemplate.delete("http://localhost:8888/book/"+ bookId, Collections.EMPTY_MAP); //Try to fetch from the DB directly Book bookFromDb = bookRepository.findOne(bookId); //and assert that there is no data found assertNull(bookFromDb); }
Testing the Get All Books API
@Test public void testGetAllBooksApi(){ //Add some test data for the API Book book1 = new Book("Book1", "ISBN1", "Author1", 200); bookRepository.save(book1); Book book2 = new Book("Book2", "ISBN2", "Author2", 200); bookRepository.save(book2); //Invoke the API Map<String, Object> apiResponse = restTemplate.getForObject("http://localhost:8888/book", Map.class); //Assert the response from the API int totalBooks = Integer.parseInt(apiResponse.get("totalBooks").toString()); assertTrue(totalBooks == 2); List<Map<String, Object>> booksList = (List<Map<String, Object>>)apiResponse.get("books"); assertTrue(booksList.size() == 2); //Delete the test data created bookRepository.delete(book1.getId()); bookRepository.delete(book2.getId()); }
The above code examples are just a part of the whole examples. You can refer my Github page to use the whole sample application on REST integration testing with Spring Book. If you have any questions, please write it in the comments section.
Hope this post gives some clarity on how to write the integration testing REST API in Spring Boot application. This code base along with its relevant REST API code can be found on GitHub here.