With Mockito we can Mock an object, stub some of it’s methods but not the other and still be able to call a real method of this stubbed object. In the code example below I am going to share with you how to call a real method of a mocked object using Mockito’s thenCallRealMethod().
In my previous blog post I have shared with you how to Test RESTful Web Service with jUnit and Mockito. The example below will be much simpler and shorter. But if you would like to learn how to add support for JUnit and Mockito to your RESTful Web Service check our this blog post.
The Object to Be Mocked
Below is an example of Plain Old Java Object which is being used to persist user details into a database. A bit later when working on a test case, we will mock this object, stub two of it’s method’s which are the getFirstName() and the getLastName() and the getFullName() will be called as a real method rather than stubbed.
package com.appsdeveloperblog.ws.io.entity; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; /** * * @author skargopolov */ @Entity(name = "Profile") public class UserProfileEntity implements Serializable { private static final long serialVersionUID = 7290798953394355234L; @Id @GeneratedValue private long id; private String firstName; private String lastName; private String fullName; /** * @return the firstName */ public String getFirstName() { return firstName; } /** * @param firstName the firstName to set */ public void setFirstName(String firstName) { this.firstName = firstName; } /** * @return the lastName */ public String getLastName() { return lastName; } /** * @param lastName the lastName to set */ public void setLastName(String lastName) { this.lastName = lastName; } /** * @return the id */ public long getId() { return id; } /** * @param id the id to set */ public void setId(long id) { this.id = id; } /** * @return the fullName */ public String getFullName() { if (fullName == null) { fullName = getFirstName() + " " + getLastName(); } return fullName; } /** * @param fullName the fullName to set */ public void setFullName(String fullName) { this.fullName = fullName; } }
Use Mockito to Mock an Object
To Mock UserProfileEntity object we will annotate it with @Mock annotation and will call the MockitoAnnotations.initMocks(this); in the setUp() method like so:
@Mock UserProfileEntity userProfileEntity; @Before public void setUp() { MockitoAnnotations.initMocks(this); }
Stubbing Mock Object with Mockito
We have Mocked the UserProfileEntity and now we can stub two of its method but call a real method on the other one.
// Stubbinb userProfileEntity methods when( userProfileEntity.getFirstName() ).thenReturn( "Sergey" ); when( userProfileEntity.getLastName()).thenReturn( "Kargopolov" ); when( userProfileEntity.getId() ).thenReturn( new Long(1) );
Use Mockito thenCallRealMethod()
// Call a real method of a Mocked object when( userProfileEntity.getFullName() ).thenCallRealMethod();
Test Class Complete Example
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ 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 testSaveUserWithFullName() { //Stubbing Database open and close methods doNothing().when(database).openConnection(); doNothing().when(database).closeConnection(); // Stubbing userProfileEntity methods when( userProfileEntity.getFirstName() ).thenReturn( "Sergey" ); when( userProfileEntity.getLastName()).thenReturn( "Kargopolov" ); when( userProfileEntity.getId() ).thenReturn( new Long(1) ); when( userProfileEntity.getFullName() ).thenCallRealMethod(); // Stubbing database saveUserProfile method when( database.saveUserProfile( any(UserProfileEntity.class) ) ).thenReturn( userProfileEntity ); // Create sample UserProfileDto UserProfileDto userProfileDto = new UserProfileDto(); userProfileDto.setFirstName( "Sergey" ); userProfileDto.setLastName( "Kargopolov" ); userProfileDto.setFullName( "Sergey 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() ); Assert.assertNotNull( result.getFullName() ); Assert.assertEquals( userProfileEntity.getFullName() , result.getFullName() ); } }
I hope this little code example was helpful to you.
To learn more about how to use JUnit and Mockito frameworks to test your Restful Web Services check out these video courses and books below:
Testing Your Code with JUnit
JUnit and Mockito Crash Course
Learn how to use JUnit and Mockito and Unit Test in easy steps.
Mockito Tutorial : Learn mocking with 25 Junit Examples
Learn unit testing and mocking with 25 Junit Examples
Happy learning!
I my case it does not work because the real method call also a injected (mocked) class which is null during test execution.
Is there something more I can do?
I mocked the already the internal injected class in my test.