Junit for REST Web Service using Spring Boot
Dependency needed for this project:
- Web
- MySQL
- JPA
- Test
- Spring-boot-maven-plugin
@WebMvcTest which is used for
testing Spring MVC application. For this test, we will focus on testing the
Controller class.
@RunWith(SpringRunner.class)
: SpringRunner is a form of SpringJUnit4ClassRunner
which extends BlockJUnit4ClassRunner and provides the functionality to launch a
Spring Test Context Framework.
@Autowired private
MockMvc mockMvc : MockMvc is main entrance for server-side Spring MVC test
support. It helps us to execute requests against the test context.
@MockBean
private CustomerService customerService:
MockBean is used to add mocks to a Spring ApplicationContext. A mock of
customerService is created and auto-wired into the CustomerController.
JSONAssert.assertEquals(): We can use org.skyscreamer.jsonassert.JSONAssert which allows us to do partial asserts against a String of JSON type. We can pass strict as false since we do not want to check for all fields in the response.
1. 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>com.gaurav</groupId>
<artifactId>JunitWithSpringBoot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>JunitWithSpringBoot</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. Customer.java
package com.gaurav.spring.bean;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "Customer")
public class Customer {
public Customer(){
}
public Customer(int id, String firstName, String lastName, String gender, int age) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.age = age;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "gender")
private String gender;
@Column(name = "age")
private int age;
public int getId() {
return id;
}
public void setId(int 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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Customer other = (Customer) obj;
if (id != other.id)
return false;
return true;
}
}
3. CustomerDao.java
package com.gaurav.spring.dao;
import java.util.List;
import com.gaurav.spring.bean.Customer;
public interface CustomerDao {
public Integer addCustomer(Customer customer);
public List<Customer> getCustomer();
public Customer findById(int id);
public Customer update(Customer customer, int id);
public boolean delete(int id);
}
4. CustomerDaoImpl.java
package com.gaurav.spring.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.gaurav.spring.bean.Customer;
@Repository
public class CustomerDaoImpl implements CustomerDao {
@Autowired
private SessionFactory sessionFactory;
public Integer addCustomer(Customer customer) {
Session session = sessionFactory.getCurrentSession();
Integer id = (Integer)session.save(customer);
System.out.println("Generated Identifier is:"+id);
System.out.println("after customer : customer id's = "+customer.getId());
return id;
}
@SuppressWarnings("unchecked")
public List<Customer> getCustomer() {
Session session = sessionFactory.getCurrentSession();
List<Customer> list = session.createCriteria(Customer.class).list();
return list;
}
public Customer findById(int id) {
Session session = sessionFactory.getCurrentSession();
Customer customer = (Customer) session.get(Customer.class, id);
return customer;
}
public Customer update(Customer customerObj, int id) {
Session session = sessionFactory.getCurrentSession();
Customer customer = (Customer) session.get(Customer.class, id);
customer.setFirstName(customerObj.getFirstName());
customer.setLastName(customerObj.getLastName());
customer.setGender(customerObj.getGender());
customer.setAge(customerObj.getAge());
session.update(customer);
return customer;
}
public boolean delete(int id) {
boolean isExistsAndDeleted = false;
Session session = sessionFactory.getCurrentSession();
Customer customer = findById(id);
if (customer != null) {
session.delete(customer);
isExistsAndDeleted = true;
}
return isExistsAndDeleted;
}
}
5. CustomerService.java
package com.gaurav.spring.service;
import java.util.List;
import com.gaurav.spring.bean.Customer;
public interface CustomerService {
public Integer createCustomer(Customer customer);
public List<Customer> getCustomer();
public Customer findById(int id);
public Customer update(Customer customer, int id);
public boolean deleteCustomerById(int id);
}
/** Transaction Management */
6. CustomerServiceImpl.java
package com.gaurav.spring.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gaurav.spring.bean.Customer;
import com.gaurav.spring.dao.CustomerDao;
@Service
@Transactional
public class CustomerServiceImpl implements CustomerService {
@Autowired
CustomerDao customerDao;
@Transactional(propagation=Propagation.SUPPORTS)
public List<Customer> getCustomer() {
return customerDao.getCustomer();
}
@Transactional(propagation=Propagation.SUPPORTS)
public Customer findById(int id) {
return customerDao.findById(id);
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public Integer createCustomer(Customer customer) {
Integer custId = customerDao.addCustomer(customer);
return custId;
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public boolean deleteCustomerById(int id) {
boolean isDeleted = customerDao.delete(id);
return isDeleted;
}
@Transactional(propagation=Propagation.REQUIRED)
public Customer update(Customer customer, int id) {
return customerDao.update(customer, id);
}
}
7. CustomerController.java
package com.gaurav.spring.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.RestController;
import org.springframework.web.util.UriComponentsBuilder;
import com.gaurav.spring.bean.Customer;
import com.gaurav.spring.service.CustomerService;
@RestController
@RequestMapping(value = { "/customer" })
public class CustomerController {
@Autowired
CustomerService customerService;
@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Customer> getCustomerById(@PathVariable("id") int id) {
System.out.println("Fetching customer with id " + id);
Customer customer = customerService.findById(id);
if (customer == null) {
return new ResponseEntity<Customer>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<Customer>(customer, HttpStatus.OK);
}
@PostMapping(value = "/create", headers = "Accept=application/json")
public ResponseEntity<Void> createCustomer(@RequestBody Customer customer, UriComponentsBuilder ucBuilder) {
customerService.createCustomer(customer);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/customer/{id}").buildAndExpand(customer.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
@GetMapping(value = "/get", headers = "Accept=application/json")
public List<Customer> getAllCustomer() {
List<Customer> customers = customerService.getCustomer();
return customers;
}
@PutMapping(value = "/update", headers = "Accept=application/json")
public ResponseEntity<String> updateCustomer(@RequestBody Customer currentCustomer) {
Customer customer = customerService.findById(currentCustomer.getId());
if (customer == null) {
return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
customerService.update(currentCustomer, currentCustomer.getId());
return new ResponseEntity<String>(HttpStatus.OK);
}
@DeleteMapping(value = "/{id}", headers = "Accept=application/json")
public ResponseEntity<Customer> deleteCustomer(@PathVariable("id") int id) {
Customer customer = customerService.findById(id);
if (customer == null) {
return new ResponseEntity<Customer>(HttpStatus.NOT_FOUND);
}
customerService.deleteCustomerById(id);
return new ResponseEntity<Customer>(HttpStatus.NO_CONTENT);
}
}
8. HibernateConfiguration.java
package com.gaurav.spring.configuration;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class HibernateConfiguration {
@Value("${spring.datasource.driver}")
private String DB_DRIVER;
@Value("${spring.datasource.url}")
private String DB_URL;
@Value("${spring.datasource.username}")
private String DB_USERNAME;
@Value("${spring.datasource.password}")
private String DB_PASSWORD;
@Value("${spring.jpa.hibernate.dialect}")
private String HIBERNATE_DIALECT;
@Value("${spring.jpa.show-sql}")
private String HIBERNATE_SHOW_SQL;
@Value("${spring.jpa.hibernate.ddl-auto}")
private String HIBERNATE_HBM2DDL_AUTO;
@Value("${spring.jpa.entitymanager.packagesToScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
hibernateProperties.put("hibernate.hbm2ddl.auto", HIBERNATE_HBM2DDL_AUTO);
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
@Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory().getObject());
return txManager;
}
}
9. SpringbootWithJUnit.java
package com.gaurav;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootWithJUnit {
public static void main(String[] args) {
SpringApplication.run(SpringbootWithJUnit.class, args);
}
}
10. application.properties
logging.level.org.springframework.web=INFO
spring.datasource.driver: com.mysql.jdbc.Driver
spring.datasource.url: jdbc:mysql://localhost:3306/experimentdemo
spring.datasource.username:root
spring.datasource.password:root
spring.jpa.hibernate.dialect:org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql:true
spring.jpa.hibernate.ddl-auto :update
spring.jpa.entitymanager.packagesToScan:com.gaurav
11. CustomerControllerTest.java
package com.gaurav.spring.controller;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.gaurav.spring.bean.Customer;
import com.gaurav.spring.service.CustomerService;
@RunWith(SpringRunner.class)
@WebMvcTest(value = CustomerController.class)
public class CustomerControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
CustomerService customerService;
Customer mockCustomer = new Customer(3, "Kumar","Gaurav", "Male", 34);
List<Customer> mockCustomerList = Arrays.asList(new Customer(3, "Kumar","Gaurav", "Male", 34), new Customer(4, "Aditi","Kumari", "Female", 25));
String customerJson = "{\"id\": 2,\"firstName\": \"Maya\",\"lastName\": \"Sree\",\"gender\": \"Female\",\"age\": 35}";
/*
* We can use this block to initialize the Mockito
* @Before
public void init(){
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(customerController)
.build();
}*/
@Test
public void getCustomerById() throws Exception {
Mockito.when(
customerService.findById(Mockito.anyInt())).thenReturn(mockCustomer);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(
"/customer/3").accept(
MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println(result.getResponse());
String expected = "{id:3,firstName:Kumar,lastName:Gaurav, gender:Male, age:34}";
JSONAssert.assertEquals(expected, result.getResponse()
.getContentAsString(), false);
}
@Test
public void getAllCustomer() throws Exception {
Mockito.when(customerService.getCustomer()).thenReturn(mockCustomerList);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/customer/get").accept(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println(result.getResponse());
String expectedList = "[{\"id\":3,\"firstName\":\"Kumar\",\"lastName\":\"Gaurav\",\"gender\":\"Male\",\"age\":34},{\"id\":4,\"firstName\":\"Aditi\",\"lastName\":\"Kumari\",\"gender\":\"Female\",\"age\":25}]";
JSONAssert.assertEquals(expectedList, result.getResponse().getContentAsString(), false);
}
@Test
public void createCustomer() throws Exception{
Integer generatedId = 5;
Mockito.when(customerService.createCustomer(Mockito.anyObject())).thenReturn(generatedId);
Mockito.when(
customerService.createCustomer(Mockito.any(Customer.class))).thenReturn(mockCustomer.getId());
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/customer/create")
.accept(MediaType.APPLICATION_JSON).content(customerJson)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
assertEquals(HttpStatus.CREATED.value(), response.getStatus());
assertEquals("http://localhost/customer/2",
response.getHeader(HttpHeaders.LOCATION));
}
@Test
public void updateCustomer() throws Exception{
Customer customer = new Customer(3, "Kumar","Gaurav", "Male", 34);
String customerStr3 = "{\"id\": 3,\"firstName\": \"Kumar\",\"lastName\": \"Gaurav\",\"gender\": \"Male\",\"age\": 34}";
Mockito.when(customerService.findById(customer.getId())).thenReturn(customer);
Mockito.when(customerService.update(customer, customer.getId())).thenReturn(customer);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.put("/customer/update")
.accept(MediaType.APPLICATION_JSON).content(customerStr3)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
assertEquals(200, response.getStatus());
Mockito.verify(customerService, Mockito.times(1)).findById(customer.getId());
Mockito.verify(customerService, Mockito.times(1)).update(customer, customer.getId());
Mockito.verifyZeroInteractions(customerService);
}
@SuppressWarnings("unused")
@Test
public void deleteCustomer() throws Exception{
Customer customer = new Customer(3, "Kumar","Gaurav", "Male", 34);
String customerStr3 = "{\"id\": 3,\"firstName\": \"Kumar\",\"lastName\": \"Gaurav\",\"gender\": \"Male\",\"age\": 34}";
Mockito.when(customerService.findById(customer.getId())).thenReturn(customer);
Mockito.when(customerService.deleteCustomerById(customer.getId())).thenReturn(true);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.delete("/customer/3")
.accept(MediaType.APPLICATION_JSON).content(customerStr3)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
Mockito.verify(customerService, Mockito.times(1)).findById(customer.getId());
Mockito.verify(customerService, Mockito.times(1)).deleteCustomerById(customer.getId());
Mockito.verifyNoMoreInteractions(customerService);
}
}
URL's to test using POSTMAN or REST Client
1. POST:- http://localhost:8080/customer/create
{
"gender": "Female",
"firstName": "Simran",
"lastName": "Diva",
"age": 16
}
2. GET:- http://localhost:8080/customer/get
3. GET:- http://localhost:8080/customer/1
4. PUT:- http://localhost:8080/customer/update
{
"id":6,
"gender": "Female",
"firstName": "Sanjay",
"lastName": "Kumar",
"age": 19
}
5. DELETE:- http://localhost:8080/customer/6
I would like to thank you for the efforts you have made in writing this article about software testing. I am hoping the same best work from you in the future as well.
ReplyDeleteSoftware Testing Services
Software Testing Services in USA
Software Testing Companies in USA
Software Testing Services in India
Software Testing Companies
Software Testing Services Company
Functional Testing Services
Performance Testing Services
Test Automation Services
Security Testing Services
API Testing Services