Saturday, 18 April 2020

Spring boot JUnit example with RestTemplate

Learn to write Junit tests in spring boot applications. Also learn to use RestTemplate to invoke REST APIs and verify test results in success and error scenarios in this spring boot junit tutorial.
To create the rest apis, use the sourcecode provided in spring boot 2 rest api example.
By default, Spring boot uses Junit 4. To write tests in Junit 5, read this migration guide : Junit 5 with Spring boot 2.

1. Maven dependencies

Make sure to have spring-boot-starter-test dependency in the project to be able to execute unit tests.
pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

2. Spring boot JUnit Test Class

A Junit test class in Spring boot application can be written like this.
SpringBootDemoApplicationTests.java
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class SpringBootDemoApplicationTests
{
    @LocalServerPort
    int randomServerPort;
     
    @Test
    public void testGetEmployeeListSuccess() throws URISyntaxException
    {
    
}
Let’s note down important things here.
  1. @RunWith(SpringRunner.class) – tells JUnit to run using Spring’s testing support. SpringRunner is the new name for SpringJUnit4ClassRunner. It enables full support of spring context loading and dependency injection of the beans in the tests.
  2. @SpringBootTest – annotation that can be specified on a test class that runs Spring Boot based tests. It provides ability to start a fully running web server listening on any defined or random port.
  3. webEnvironment – enables requests and responses to travel over network and mock servlet container is not involved.
  4. @LocalServerPort – injects the HTTP port that got allocated at runtime.

3. Spring boot JUnit example

In given below example, I will first write the rest api code and then unit test which invoke the rest api and verify api response.

3.1. HTTP GET API

3.1.1. REST API Code
REST API which return the list of all employees in list.
API Code
@GetMapping(path="/employees", produces = "application/json")
public Employees getEmployees()
{
    return employeeDao.getAllEmployees();
}
3.1.2. Junit Test
Junit test with RestTemplate which invoke above API and verify the api response code as well as response body.
Junit Test
@Test
public void testGetEmployeeListSuccess() throws URISyntaxException
{
    RestTemplate restTemplate = new RestTemplate();
     
    final String baseUrl = "http://localhost:" + randomServerPort + "/employees";
    URI uri = new URI(baseUrl);
    ResponseEntity<String> result = restTemplate.getForEntity(uri, String.class);
     
    //Verify request succeed
    Assert.assertEquals(200, result.getStatusCodeValue());
    Assert.assertEquals(true, result.getBody().contains("employeeList"));
}

3.2. HTTP POST API

3.2.1. REST API Code
REST API which add an employee to employee collection.
API Code
@PostMapping(path= "/employees",
                consumes = "application/json",
                produces = "application/json")
public ResponseEntity<Object> addEmployee
(
    @RequestHeader(name = "X-COM-PERSIST", required = true) String headerPersist,
    @RequestHeader(name = "X-COM-LOCATION", defaultValue = "ASIA") String headerLocation,
    @RequestBody Employee employee
)   throws Exception
{      
    //Generate resource id
    Integer id = employeeDao.getAllEmployees().getEmployeeList().size() + 1;
    employee.setId(id);
     
    //add resource
    employeeDao.addEmployee(employee);
     
    //Create resource location
    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
                                .path("/{id}")
                                .buildAndExpand(employee.getId())
                                .toUri();
     
    //Send location in response
    return ResponseEntity.created(location).build();
}
3.2.2. Junit test – success scenario
Junit test with RestTemplate which invoke above API and verify the api response code as well as response body.
Junit Test
@Test
public void testGetEmployeeListSuccess() throws URISyntaxException
{
    RestTemplate restTemplate = new RestTemplate();
     
    final String baseUrl = "http://localhost:" + randomServerPort + "/employees";
    URI uri = new URI(baseUrl);
    ResponseEntity<String> result = restTemplate.getForEntity(uri, String.class);
     
    //Verify request succeed
    Assert.assertEquals(200, result.getStatusCodeValue());
    Assert.assertEquals(true, result.getBody().contains("employeeList"));
}
3.2.3. Junit test – error scenario
Junit test which expects an error when there is a missing header in the request.
Junit Test
@Test
public void testAddEmployeeMissingHeader() throws URISyntaxException
{
    RestTemplate restTemplate = new RestTemplate();
    final String baseUrl = "http://localhost:"+randomServerPort+"/employees/";
    URI uri = new URI(baseUrl);
    Employee employee = new Employee(null, "Adam", "Gilly", "test@email.com");
     
    HttpHeaders headers = new HttpHeaders();
    HttpEntity<Employee> request = new HttpEntity<>(employee, headers);
     
    try
    {
        restTemplate.postForEntity(uri, request, String.class);
        Assert.fail();
    }
    catch(HttpClientErrorException ex)
    {
        //Verify bad request and missing header
        Assert.assertEquals(400, ex.getRawStatusCode());
        Assert.assertEquals(true, ex.getResponseBodyAsString().contains("Missing request header"));
    }
}

3.3. Execute JUnit tests

Run the class as Junit test and watch for result.

Junit Test Results
Junit Test Results

Let me know if you have any query in this spring boot rest controller junit test example.

No comments:

Post a Comment