Why trying to spy on method is calling the original method in Mockito

May 03, 2022 No comments Mockito Java Spy JUnit

1. Introduction

In this article, we will focus on a case when the original method is called even though we use Mockito to configure a different behavior.

2. Testing class

Let's use a simple class ThrowingService to show our case:

package com.frontbackend.libraries.mockito.service;

public class ThrowingService {

    public void someVoidMethod(int value) {
        System.out.println(1000 / value);
    }

    public int someNotVoidMethod(int value) {
        return 10000 / value;
    }
}

This class has two methods: one that returns the int value and one void method.

3. JUnit test

In the following example test we used when(...).thenReturn(...) statement to change the return value when called someNotVoidMethod(...) method on ThrowingService object:

package com.frontbackend.libraries.mockito;

import com.frontbackend.libraries.mockito.service.ThrowingService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoSpyCallsOriginalMethod {

    public ThrowingService instance = new ThrowingService();

    @Test(expected = ArithmeticException.class)
    public void thisMethodWillThrowArithmeticException() {
        ThrowingService throwingService = Mockito.spy(instance);
        Mockito.when(throwingService.someNotVoidMethod(0))
                .thenReturn(1000);
        throwingService.someNotVoidMethod(0);
    }
}

Unfortunately, the original throwingService.someNotVoidMethod(0) method will be called in this case and the ArithmeticException will be thrown because we send 0 as an argument to that method, and we cannot be dived by zero.

Note that we will not have that issue with mock. The following code will not throw an ArithmeticException:

public void thisMethodWillThrowNotArithmeticException() {
    ThrowingService throwingService = Mockito.mock(ThrowingService.class);
    Mockito.when(throwingService.someNotVoidMethod(0))
            .thenReturn(1000);
    throwingService.someNotVoidMethod(0);        
}

How to fix our test?

We need to use doReturn(...).when(...).method(...):

package com.frontbackend.libraries.mockito;

import com.frontbackend.libraries.mockito.service.ThrowingService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoSpyCallsOriginalMethod {

    public ThrowingService instance = new ThrowingService();

    @Test
    public void thisMethodWillNotThrowArithmeticException() {
        ThrowingService throwingService = Mockito.spy(instance);
        Mockito.doReturn(1000)
                .when(throwingService)
                .someNotVoidMethod(0);
        int value = throwingService.someNotVoidMethod(0);
        Assert.assertEquals(1000, value);
    }
}

The important thing to remember here is:

  • Please use doReturn() family of methods when stubbing a method using spies,
  • when(...) would result in calling the actual method that can throw exceptions.

4. Conclusion

In this article, we presented a case where a real method on a spied object was called when we try to configure it using Mockito.

As usual, code introduced in this article is available in our GitHub repository.

{{ message }}

{{ 'Comments are closed.' | trans }}