Mockito – Call a Real Method

Mockito enables partial mocking of an object, allowing us to create a mock object while still invoking a real method. To achieve this, we can use Mockito’s thenCallRealMethod() method to call a real method on a mocked object.

I have also created several step-by-step video lessons that demonstrate how to test Java applications. If you are interested in learning more, you can check out my video course titled ‘Testing Java with JUnit and Mockito‘.

The Object to Be Mocked

Here is an example of a Plain Old Java Object (POJO) being used to store user details in a database. When working on a test case later, we will mock this object and stub two of its methods, namely getFirstName() and getLastName(). However, the getFullName() method will be called as a real method instead of being 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 the UserProfileEntity object, we will annotate it with the @Mock annotation and call the MockitoAnnotations.initMocks(this) method in the setUp() method, as shown below:

@Mock
UserProfileEntity userProfileEntity;

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

Stubbing Mock Object with Mockito

Now that you have learned how to mock UserProfileEntity, let’s continue and learn how to stub it with predefined values.

// Stubbinb userProfileEntity methods
when( userProfileEntity.getFirstName() ).thenReturn( "Sergey" );
when( userProfileEntity.getLastName()).thenReturn( "Kargopolov" );
when( userProfileEntity.getId() ).thenReturn( new Long(1) );

Call a Real Method

In Mockito, to invoke a real method of a mock object, we can use the thenCallRealMethod() method.

// 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() );
    }
}

Handling Exceptions with thenCallRealMethod()

When using Mockito’s thenCallRealMethod() method, it’s important to consider what will happen if the real method being called throws an exception. If this occurs, the exception will be thrown and propagated up the call stack, just as it would if the method were called normally.

To handle the exception and perform assertions on it, you can use Mockito’s try-catch syntax. Here’s an example:

@Test
public void testRealMethodThrowsException() {
    MyClass myClassMock = Mockito.mock(MyClass.class);
    Mockito.when(myClassMock.getValue()).thenCallRealMethod();

    try {
        int result = myClassMock.getValue();
        fail("Expected an exception to be thrown");
    } catch (MyException ex) {
        assertEquals("Expected exception message", ex.getMessage());
    }
}

In this example, we’re testing a method called getValue() on a mocked instance of MyClass. We’re using thenCallRealMethod() to call the real implementation of getValue(), which we know will throw a MyException under certain circumstances.

To test this behaviour, we use Mockito’s fail() method to signal that we expect an exception to be thrown. Then, we wrap the call to myClassMock.getValue() in a try-catch block, catching the expected MyException and performing assertions on its message.

It’s worth noting that if you’re using thenCallRealMethod() to call a method that throws a checked exception, you’ll need to add the exception to your test method’s throws clause. For example:

@Test(expected = MyCheckedException.class)
public void testRealMethodThrowsCheckedException() throws MyCheckedException {
    MyClass myClassMock = Mockito.mock(MyClass.class);
    Mockito.when(myClassMock.getValue()).thenCallRealMethod();

    int result = myClassMock.getValue();
}

In this example, we’re using the expected attribute of the @Test annotation to specify that we expect a MyCheckedException to be thrown by the real implementation of getValue(). We’ve also added throws MyCheckedException to the method, signature to satisfy Java’s checked exception handling requirements.

By understanding how to handle exceptions when using thenCallRealMethod(), you can write more robust and effective unit tests that account for unexpected behaviour in your code.

Mockito’s thenCallRealMethod() vs spy() method

Both Mockito’s spy() and thenCallRealMethod() methods can be used to partially mock an object, but they serve different purposes and should be used in different scenarios.

A spy is a real object that is being spied on, with some methods being mocked while others remain unmocked. When using a spy, you can selectively mock methods that you want to change the behaviour of, while other methods will continue to behave normally. This can be useful if you need to test some methods of a complex object while still using the actual implementation of other methods.

On the other hand, thenCallRealMethod() is used to invoke the real method of a mock object instead of a stubbed method. This is useful when you want to test the actual implementation of a method while still using a mock object. It can be helpful if you want to test a particular method in isolation while still mocking other parts of the code.

In general, you should use a spy when you want to test a specific object with some complex behaviour, but you still want to test the actual implementation of some of its methods. You should use thenCallRealMethod() when testing a single method in isolation while still using a mock object for the other parts of the code.

In summary, a spy should be used when you want to test a specific object that has some complex behaviour but you still want to test the actual implementation of some of its methods. When you want to test a single method in isolation while still using a mock object for the other parts of the code, you should use thenCallRealMethod().

Conclusion

In conclusion, Mockito is a powerful mocking framework that allows developers to create mock objects and define their behaviors during testing. One aspect of Mockito is the ability to call a real method on a mock object, which can be useful in certain scenarios.

Unlock the potential of Mockito and enhance your testing prowess. Visit the Testing Java Code page for a wide range of Mockito tutorials that will empower you to write comprehensive tests, mock dependencies effortlessly, and ensure the reliability of your Java applications.

Frequently asked questions

  • How can I verify that a real method was called when using thenCallRealMethod()?
    You can use Mockito’s verify() method to verify that the method was called with the expected arguments. However, you cannot use verify() to verify that the method’s return value was correct, since the method’s real implementation is being called.
  • Can I use thenCallRealMethod() to call a private method?
    No, thenCallRealMethod() can only be used to call public or protected methods. If you need to call a private method, you can use the Reflection API to set the method’s accessibility and then invoke it. However, this is not recommended as it can lead to brittle tests that break easily if the implementation details of the class change.
  • Is it possible to use thenCallRealMethod() with void methods?
    No, thenCallRealMethod() can only be used with non-void methods. For void methods, you can use doCallRealMethod() instead.

1 Comment on "Mockito – Call a Real Method"


  1. 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.

    Reply

Leave a Reply

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