Earlier I’ve published a blog post on now to create a RESTful Web Service(JAX-RS) to accept JSON payload with user profile details and how to save user profile details into a MySQL database using Java Hibernate framework. In this blog post I am going to share with you how to test(using JUnit and Mockito) it’s Service Layer Implementation class, which is responsible for storing user profile details. Below, is a short break down on things we are going to cover:
- Add Mockito Framework for Unit tests mockito-core to our project pom.xml file
- Add Spring Framework spring-test and spring-context dependencies
- Create Spring ContextConfiguration Java class to specify base packages for component scanning
- Create UsersServiceImplTest class, Autowire service class, mock objects, call saveUser method and Assert expected results.
Ok, let’s begin.
Add mockito-core, spring-test and spring-context to pom.xml
Open https://mvnrepository.com and search each of the below libraries Maven repository. Below are the ones I have copied into my pom.xml:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.8.47</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.7.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.7.RELEASE</version> </dependency>
The above dependencies should allow you to autowire Spring Beans into your Test class and Mock objects and their behaviour. After adding the above to my pom.xml file, the complete pom.xml of my RESTful Web Services app looks like this:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.appsdeveloperblog.ws</groupId> <artifactId>HibernateExamples</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>HibernateExamples Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.8.47</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.bundles/jaxrs-ri --> <dependency> <groupId>org.glassfish.jersey.bundles</groupId> <artifactId>jaxrs-ri</artifactId> <version>2.25</version> </dependency> <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-moxy --> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId> <version>2.25</version> </dependency> <!-- Hibernate Dependencies --> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.8.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.0.Final</version> </dependency> <!-- MySQL Dependencies --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.41</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.7.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.1.Final</version> </dependency> </dependencies> <build> <finalName>HibernateExamples</finalName> </build> </project>
Create Spring ContextConfiguration Class
To be able to @Autowire classes into my Test class, I need to create a new Java class with @Configuration annotation and specify the base package name which will be used by @ComponentScan to find all the Spring Beans which can be autowired. This class needs to be created in a package under the Tests folder in your project.
package com.appsdeveloperblog.ws; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = {"com.appsdeveloperblog.ws"}) public class TestConfiguration { }
The UsersServiceImpl class
Please note the use of @Service(“usersService”) above the class name. The value you specify in @Service annotation should match the value you specify in @Qualifier(“usersService”) when you are auto wiring the Spring Bean in your Test class. Thus the values of @Service(“usersService”) and @Qualifier(“usersService”) in my case match.
Below is my version of the Service class which I am testing with the UsersServiceImplTest class the code of which I am also going to paste below.
package com.appsdeveloperblog.ws.service.impl; import com.appsdeveloperblog.ws.io.dao.Database; import com.appsdeveloperblog.ws.io.entity.UserProfileEntity; import com.appsdeveloperblog.ws.service.UsersService; import com.appsdeveloperblog.ws.shared.dto.UserProfileDto; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; @Service("usersService") public class UsersServiceImpl implements UsersService { Database database; public UserProfileDto saveUser(UserProfileDto userDto) { UserProfileDto returnValue = null; UserProfileEntity userEntity = new UserProfileEntity(); BeanUtils.copyProperties(userDto, userEntity); // Connect to database try { this.database.openConnection(); UserProfileEntity storedUserEntity = this.database.saveUserProfile(userEntity); if(storedUserEntity != null && storedUserEntity.getId()>0) { returnValue = new UserProfileDto(); BeanUtils.copyProperties(storedUserEntity, returnValue); } } finally { this.database.closeConnection(); } return returnValue; } }
Create the Test class, Autowire Service Class and Mock objects
Because we are creating a test class for UsersServiceImpl class, the name of our test class will be UsersServiceImplTest.
In the code below please note that we are going to test the saveUser() method of UsersService. This is why we add the @Autowired and the @InjectMocks on UsersService object declaration and then we simply mock all other objects and their methods.
Also, please notice the use of @Qualifier(“usersService”). Inside of the @Qualifier annotation we need to specify the value which we have specified in the @Service annotation in the UsersServiceImpl class above.
Below is a complete UsersServiceImplTest class which is testing the saveUser() method of UsersServiceImpl class.
package com.appsdeveloperblog.ws.service.impl; import com.appsdeveloperblog.ws.TestConfiguration; import com.appsdeveloperblog.ws.io.dao.Database; import com.appsdeveloperblog.ws.io.entity.UserProfileEntity; import com.appsdeveloperblog.ws.service.UsersService; import com.appsdeveloperblog.ws.shared.dto.UserProfileDto; import org.junit.*; import org.junit.runner.RunWith; import static org.mockito.ArgumentMatchers.any; import org.mockito.InjectMocks; import org.mockito.Mock; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = TestConfiguration.class ) public class UsersServiceImplTest { @Mock Database database; @Mock UserProfileEntity userProfileEntity; @Autowired @InjectMocks @Qualifier("usersService") UsersService usersService; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testSaveUser() { System.out.println("testing saveUser"); //Mocking Database open and close methods doNothing().when(database).openConnection(); doNothing().when(database).closeConnection(); // Mocking userProfileEntity methods when( userProfileEntity.getFirstName() ).thenReturn( "Sergey" ); when( userProfileEntity.getLastName()).thenReturn( "Kargopolov" ); when( userProfileEntity.getId() ).thenReturn( new Long(1) ); // Mocking database saveUserProfile method when( database.saveUserProfile( any(UserProfileEntity.class) ) ).thenReturn( userProfileEntity ); // Create sample UserProfileDto UserProfileDto userProfileDto = new UserProfileDto(); userProfileDto.setFirstName( "Sergey" ); userProfileDto.setLastName( "Kargopolov" ); // Call saveUser method UserProfileDto result = usersService.saveUser( userProfileDto ); // Assert expected results Assert.assertNotNull( result ); Assert.assertEquals( userProfileDto.getFirstName() , result.getFirstName() ); Assert.assertEquals( userProfileDto.getLastName() , result.getLastName() ); } }
And this is it. Following the code example in this blog post, you can create Unit tests with JUnit and Mockito for any of your Service layer classes in the project.
Happy learning!