Hey guys in this post, we will learn about writing JUnit integration test cases for Spring Boot REST API. In the previous posts, we discussed writing the JUnit test cases for the Repository layer, Service layer, and Controller layer for the Spring Boot application, in case you miss those posts, you can check them now.
Integration testing is nothing but end-to-end testing, we will write the test cases to test the real implementation with real databases like MySQL, PostgreSQL, etc.
Writing Spring Boot REST API Integration testing with JUnit 5 is one of the most common things that we do every day in our day-to-day development. Most developers struggle in writing these integration test cases so this is the article for the spring boot rest api integration test example, follow this post till the end.
Read More:
- Check the Complete JUnit 5 Tutorial
- Check the Complete JavaServer Faces (JSF) Tutorial
- Check the Spring Boot JdbcTemplate Tutorials
- Check the Complete Spring Boot and Data JPA Tutorials
- Check the Complete Spring MVC Tutorials
- Check the Complete JSP Tutorials
- Check the Complete Spring Boot Tutorials [100+ Examples]
- Check the Complete Spring Boot and Thymeleaf Tutorial
- Check the Complete AWS Tutorial
- Check the Complete JavaServer Faces (JSF) Tutorial
- Check the Complete Spring Data JPA Tutorial
- Check the Complete Spring Security Tutorial
- Check the Javascript Projects for Beginners
Table of Contents
Watch the Video
Configure datasource
Let’s configure the datasource for the MySQL database open application.properties
and add the following content
spring.jpa.show-sql=true
spring.datasource.url=jdbc:mysql://localhost:3306/moviesdb
spring.datasource.username=root
spring.datasource.password=scbushan05
spring.jpa.hibernate.ddl-auto=update
Create JPA Entity
Let’s create an JPA entity Movie.java
inside in.bushansirgur.springbootjunit.model
and add the following content
package in.bushansirgur.springbootjunit.model;
import java.time.LocalDate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "tbl_movies")
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String genera;
private LocalDate releaseDate;
}
Create JPA Repository
Let’s create an interface MovieRepository.java
inside in.bushansirgur.springbootjunit.repository
and add the following content
package in.bushansirgur.springbootjunit.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import in.bushansirgur.springbootjunit.model.Movie;
public interface MovieRepository extends JpaRepository<Movie, Long>{
List<Movie> findByGenera(String genera);
}
Create a Service
Let’s create a class MovieService.java
inside in.bushansirgur.springbootjunit.service
and add the following content
package in.bushansirgur.springbootjunit.service;
import java.util.List;
import org.springframework.stereotype.Service;
import in.bushansirgur.springbootjunit.model.Movie;
import in.bushansirgur.springbootjunit.repository.MovieRepository;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class MovieService {
private final MovieRepository movieRepository;
public Movie save(Movie movie) {
return movieRepository.save(movie);
}
public List<Movie> getAllMovies() {
return movieRepository.findAll();
}
public Movie getMovieById(Long id) {
return movieRepository.findById(id).orElseThrow(() -> new RuntimeException("Movie found for the id "+id));
}
public Movie updateMovie(Movie movie, Long id) {
Movie existingMovie = movieRepository.findById(id).get();
existingMovie.setGenera(movie.getGenera());
existingMovie.setName(movie.getName());
existingMovie.setReleaseDate(movie.getReleaseDate());
return movieRepository.save(existingMovie);
}
public void deleteMovie(Long id) {
Movie existingMovie = movieRepository.findById(id).get();
movieRepository.delete(existingMovie);
}
}
Create a Controller
Let’s create a class MovieController.java
inside in.bushansirgur.springbootjunit.controller
and add the following content
package in.bushansirgur.springbootjunit.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import in.bushansirgur.springbootjunit.model.Movie;
import in.bushansirgur.springbootjunit.service.MovieService;
@RestController
@RequestMapping("/movies")
public class MovieController {
@Autowired
private MovieService movieService;
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Movie create(@RequestBody Movie movie) {
return movieService.save(movie);
}
@GetMapping
@ResponseStatus(HttpStatus.OK)
public List<Movie> read() {
return movieService.getAllMovies();
}
@GetMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public Movie read(@PathVariable Long id) {
return movieService.getMovieById(id);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
movieService.deleteMovie(id);
}
@ResponseStatus(HttpStatus.OK)
@PutMapping("/{id}")
public Movie update(@PathVariable Long id, @RequestBody Movie movie) {
return movieService.updateMovie(movie, id);
}
}
Now we need to write integration test cases to test these REST APIs
Create JUnit class
In order to write the integration test cases create a JUnit class MoviesIntegrationTest.java
inside src/test/java
and add the following content
package in.bushansirgur.springbootjunit.integration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.web.client.RestTemplate;
import in.bushansirgur.springbootjunit.model.Movie;
import in.bushansirgur.springbootjunit.repository.MovieRepository;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MoviesIntegrartionTest {
@LocalServerPort
private int port;
private String baseUrl = "http://localhost";
private static RestTemplate restTemplate;
private Movie avatarMovie;
private Movie titanicMovie;
@Autowired
private MovieRepository movieRepository;
@BeforeAll
public static void init() {
restTemplate = new RestTemplate();
}
@BeforeEach
public void beforeSetup() {
baseUrl = baseUrl + ":" +port + "/movies";
avatarMovie = new Movie();
avatarMovie.setName("Avatar");
avatarMovie.setGenera("Action");
avatarMovie.setReleaseDate(LocalDate.of(2000, Month.APRIL, 22));
titanicMovie = new Movie();
titanicMovie.setName("Titanic");
titanicMovie.setGenera("Romance");
titanicMovie.setReleaseDate(LocalDate.of(1999, Month.MAY, 20));
avatarMovie = movieRepository.save(avatarMovie);
titanicMovie = movieRepository.save(titanicMovie);
}
@AfterEach
public void afterSetup() {
movieRepository.deleteAll();
}
@Test
void shouldCreateMovieTest() {
Movie avatarMovie = new Movie();
avatarMovie.setName("Avatar");
avatarMovie.setGenera("Action");
avatarMovie.setReleaseDate(LocalDate.of(2000, Month.APRIL, 22));
Movie newMovie = restTemplate.postForObject(baseUrl, avatarMovie, Movie.class);
assertNotNull(newMovie);
assertThat(newMovie.getId()).isNotNull();
}
@Test
void shouldFetchMoviesTest() {
List<Movie> list = restTemplate.getForObject(baseUrl, List.class);
assertThat(list.size()).isEqualTo(2);
}
@Test
void shouldFetchOneMovieTest() {
Movie existingMovie = restTemplate.getForObject(baseUrl+"/"+avatarMovie.getId(), Movie.class);
assertNotNull(existingMovie);
assertEquals("Avatar", existingMovie.getName());
}
@Test
void shouldDeleteMovieTest() {
restTemplate.delete(baseUrl+"/"+avatarMovie.getId());
int count = movieRepository.findAll().size();
assertEquals(1, count);
}
@Test
void shouldUpdateMovieTest() {
avatarMovie.setGenera("Fantacy");
restTemplate.put(baseUrl+"/{id}", avatarMovie, avatarMovie.getId());
Movie existingMovie = restTemplate.getForObject(baseUrl+"/"+avatarMovie.getId(), Movie.class);
assertNotNull(existingMovie);
assertEquals("Fantacy", existingMovie.getGenera());
}
}
@SpringBootTest
: Spring Boot provides a convenient way to start up an application context to be used in a test. The@SpringBootTest
annotation tells Spring Boot to look for the main configuration class (one with@SpringBootApplication
, for instance) and use that to start a Spring application context.
(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
: With this configuration, Spring creates aWebApplicationContext
for our integration test and starts the embedded servlet container on a random ephemeral port.@LocalServerPort
: It injects the HTTP port that got allocated at runtime. Provides a convenient alternative for@Value("${local.server.port}")
Now when we run the test class, we should see the green bar
That’s it for this article, in the next article. Thank you so much for reading this post, if you feel this post helped you then consider sharing this with your friends, colleagues, and social media.