Test RESTful Web Service with JUnit and Mockito

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!

Leave a Reply

Your email address will not be published. Required fields are marked *