Friday 4 October 2019

Spring boot: Writing unit tests to the service layer

While writing unit tests to the service layer, we need to mock the underlying data access layer components. Since we are mocking data access layer components, we no need to configure any data source.

Step 1: Create a test class and make sure that you run this class with MockitoJUnitRunner.
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class EmployeeServiceUnitTest {
 .....
 .....
}

@RunWith(MockitoJUnitRunner.class)
Run this test class with MockitoJUnitRunner.

@SpringBootTest(webEnvironment = WebEnvironment.NONE)
Tell that we are not testing any controllers.

Step 2: Create mock objects that are going to be used by service component.
@Mock
private EmployeeDaoImpl empDao;

Step 3: Mark service component with @InjectMocks annotation on which injection should be performed.
@InjectMocks
private EmployeeServiceImpl empService;

Step 4: Initializes objects annotated with Mockito annotations for given testClass.
@Before
public void setup() {
         MockitoAnnotations.initMocks(this);
}

Step 5: Use mocked object while returning the results.
when(empDao.save(any(Employee.class))).thenReturn(emp1);
Employee persistedEmployee = empService.save(emp1);

Complete test class looks like below.
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class EmployeeServiceUnitTest {

 @Mock
 private EmployeeDaoImpl empDao;

 @InjectMocks
 private EmployeeServiceImpl empService;

 @Before
 public void setup() {
  MockitoAnnotations.initMocks(this);
 }

 @Test
 public void newEmployee() {
  Employee emp1 = new Employee();
  emp1.setId(1);
  emp1.setFirstName("Anil");
  emp1.setLastName("Kumar");

  when(empDao.save(any(Employee.class))).thenReturn(emp1);

  Employee persistedEmployee = empService.save(emp1);

  assertNotNull(persistedEmployee);
  assertNotNull(persistedEmployee.getId());
  assertEquals(emp1.getFirstName(), persistedEmployee.getFirstName());
  assertEquals(emp1.getLastName(), persistedEmployee.getLastName());
 }
}

Find the below working application.

Employee.java    
package com.sample.app.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {

 @Id
 @GeneratedValue
 @Column(name = "employee_name")
 private Integer id;

 @Column(name = "first_name")
 private String firstName;

 @Column(name = "last_name")
 private String lastName;

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

}

EmployeeDao.java

package com.sample.app.dao;

import java.util.List;

import com.sample.app.model.Employee;

public interface EmployeeDao {

 public Employee save(Employee emp);
 
 public List<Employee> all();
}

EmployeeDaoImpl.java    
package com.sample.app.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.sample.app.dao.EmployeeDao;
import com.sample.app.model.Employee;

@Repository
public class EmployeeDaoImpl implements EmployeeDao {
 @PersistenceContext
 private EntityManager entityManager;

 @Override
 @Transactional
 public Employee save(Employee emp) {
  entityManager.persist(emp);
  entityManager.flush();
  int id = emp.getId();

  return entityManager.find(Employee.class, id);

 }

 @Override
 public List<Employee> all() {
  Query query = entityManager.createQuery("select e from Employee e", Employee.class);
  return query.getResultList();
 }

}

EmployeeService.java
package com.sample.app.service;

import java.util.List;

import com.sample.app.model.Employee;

public interface EmployeeService {
 public Employee save(Employee emp);

 public List<Employee> all();
}

EmployeeServiceImpl.java
package com.sample.app.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sample.app.dao.EmployeeDao;
import com.sample.app.model.Employee;
import com.sample.app.service.EmployeeService;

@Service
public class EmployeeServiceImpl implements EmployeeService {

 @Autowired
 EmployeeDao empDao;

 @Override
 public Employee save(Employee emp) {
  return empDao.save(emp);
 }

 @Override
 public List<Employee> all() {
  return empDao.all();
 }

}

HomeController.java
package com.sample.app.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {
 @RequestMapping("/")
 public String homePage() {
  return "Welcome to Spring boot Application Development";
 }

}

EmployeeController.java
package com.sample.app.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.sample.app.model.Employee;
import com.sample.app.service.EmployeeService;

@RestController
@RequestMapping("api/v1/")
public class EmployeeController {

 @Autowired
 private EmployeeService empService;

 @RequestMapping(value = "employees", method = RequestMethod.GET)
 public ResponseEntity<List<Employee>> allEmployees() {
  return ResponseEntity.ok(empService.all());
 }

 @RequestMapping(value = "employees", method = RequestMethod.POST)
 public ResponseEntity<Employee> save(@RequestBody Employee emp) {
  Employee persistedEmp = empService.save(emp);
  return ResponseEntity.status(HttpStatus.CREATED).body(persistedEmp);
 }

}

App.java
package com.sample.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class App {

 public static void main(String args[]) {
  SpringApplication.run(App.class, args);
 }

}

application-test.properties
logging.level.root=WARN
logging.level.org.hibernate=ERROR

spring.datasource.url=jdbc:h2:file:~/db/appTest.db;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;

application.properties
logging.level.root=WARN
logging.level.org.hibernate=ERROR

## H2 specific properties
spring.h2.console.enabled=true
spring.h2.console.path=/h2

spring.datasource.url=jdbc:h2:file:~/db/myOrg.db;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;

spring.datasource.username=krishna
spring.datasource.password=password123

spring.datasource.driverClassName=org.h2.Driver

## JPA specific properties
# Creates the schema, destroying previous data.
spring.jpa.hibernate.ddl-auto=create

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

## Database connection pooling properties
# Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.max-wait=10000

# Maximum number of active connections that can be allocated from this pool at the same time.
spring.datasource.tomcat.max-active=10
spring.datasource.tomcat.max-idle=5
spring.datasource.tomcat.min-idle=3

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

Test classes are given below.
EmployeeServiceIntegrationTest.java
package com.sample.app.service;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.sample.app.model.Employee;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@ActiveProfiles("test")
public class EmployeeServiceIntegrationTest {
 
 @Autowired
 EmployeeService empService;
 
 @Test
 public void newEmployee() {
  Employee emp1 = new Employee();
  emp1.setFirstName("Anil");
  emp1.setLastName("Kumar");
  
  Employee persistedEmployee = empService.save(emp1);
  
  assertNotNull(persistedEmployee);
  assertNotNull(persistedEmployee.getId());
  assertEquals(emp1.getFirstName(), persistedEmployee.getFirstName());
  assertEquals(emp1.getLastName(), persistedEmployee.getLastName());
 }

}

EmployeeServiceUnitTest.java
package com.sample.app.service;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

import com.sample.app.dao.impl.EmployeeDaoImpl;
import com.sample.app.model.Employee;
import com.sample.app.service.impl.EmployeeServiceImpl;

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class package com.sample.app.service;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

import com.sample.app.dao.impl.EmployeeDaoImpl;
import com.sample.app.model.Employee;
import com.sample.app.service.impl.EmployeeServiceImpl;

@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class EmployeeServiceUnitTest {

 @Mock
 private EmployeeDaoImpl empDao;

 @InjectMocks
 private EmployeeServiceImpl empService;

 @Before
 public void setup() {
  MockitoAnnotations.initMocks(this);
 }

 @Test
 public void newEmployee() {
  Employee emp1 = new Employee();
  emp1.setId(1);
  emp1.setFirstName("Anil");
  emp1.setLastName("Kumar");

  when(empDao.save(any(Employee.class))).thenReturn(emp1);

  Employee persistedEmployee = empService.save(emp1);

  assertNotNull(persistedEmployee);
  assertNotNull(persistedEmployee.getId());
  assertEquals(emp1.getFirstName(), persistedEmployee.getFirstName());
  assertEquals(emp1.getLastName(), persistedEmployee.getLastName());
 }
}
 {

 @Mock
 private EmployeeDaoImpl empDao;

 @InjectMocks
 private EmployeeServiceImpl empService;

 @Before
 public void setup() {
  MockitoAnnotations.initMocks(this);
 }

 @Test
 public void newEmployee() {
  Employee emp1 = new Employee();
  emp1.setId(1);
  emp1.setFirstName("Anil");
  emp1.setLastName("Kumar");

  when(empDao.save(any(Employee.class))).thenReturn(emp1);

  Employee persistedEmployee = empService.save(emp1);

  assertNotNull(persistedEmployee);
  assertNotNull(persistedEmployee.getId());
  assertEquals(emp1.getFirstName(), persistedEmployee.getFirstName());
  assertEquals(emp1.getLastName(), persistedEmployee.getLastName());
 }
}


pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>springTest</groupId>
 <artifactId>springTest</artifactId>
 <version>1</version>


 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.6.RELEASE</version>
 </parent>

 <name>springbootApp</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>

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

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>


  <dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
  </dependency>

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

 </dependencies>
</project>

Total project structure looks like below.


How to run the test case?
Right click on 'EmployeeServiceUnitTest.java' and Run As -> JUnit Test.
You can download complete working application from this link.
    

Previous                                                    Next                                                    Home

No comments:

Post a Comment