489

I'm using Mockito 1.9.0. I want mock the behaviour for a single method of a class in a JUnit test, so I have

final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);

The problem is, in the second line, myClassSpy.method1() is actually getting called, resulting in an exception. The only reason I'm using mocks is so that later, whenever myClassSpy.method1() is called, the real method won't be called and the myResults object will be returned.

MyClass is an interface and myInstance is an implementation of that, if that matters.

What do I need to do to correct this spying behaviour?

adam_0
  • 6,920
  • 6
  • 40
  • 52
Dave
  • 15,639
  • 133
  • 442
  • 830

10 Answers10

823

Let me quote the official documentation:

Important gotcha on spying real objects!

Sometimes it's impossible to use when(Object) for stubbing spies. Example:

List list = new LinkedList();
List spy = spy(list);

// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

In your case it goes something like:

doReturn(resultsIWant).when(myClassSpy).method1();
Nicholas K
  • 15,148
  • 7
  • 31
  • 57
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 42
    What if I use this method and my original one is STILL getting called? Could there be problem with parameters I pass? Here is the whole test: http://pastebin.com/ZieY790P `send` method is being called – Evgeni Petrov Aug 21 '14 at 15:02
  • 36
    @EvgeniPetrov if your original method is still being called it's probably because your original method is final. Mockito doesn't mock final methods, and cannot warn you about the mocking of final methods. – Marcelo Glasberg Dec 08 '14 at 21:01
  • 1
    is this also possible for doThrow()? – Gobliins Jan 23 '15 at 13:17
  • is the final Method rule also apply to static methods , my static methods are getting called even when I use doReturn().when().myMethod() – P-RAD Jan 28 '16 at 06:35
  • Mockito can't mock static methods. http://stackoverflow.com/questions/4482315/why-does-mockito-not-mock-static-methods – Matt Apr 26 '16 at 19:40
  • 2
    yes, unfortunately static methods are unmockable and "un-spy-able". What I do to deal with static methods is to wrap a method around the static call and use a doNothing or doReturn on that method. With singletons or scala objects I move the meat of the logic to an abstract class and that gives me the ability to have an alternate test class impl of the object that I can create a spy on. – Andrew Norman Oct 13 '16 at 22:59
  • 48
    And what if the NOT final and NOT static method is still getting called? – X-HuMan Oct 27 '16 at 11:30
  • 1
    I had this issue when tried to spy on a static method and mock it, what I did was: `PowerMockito.spy(ClassToMock.class); PowerMockito.doAnswer(i -> getValueToReturn()).when(ClassToMock.class, "methodToMock");` – Ofek Agmon Jul 19 '18 at 10:39
  • Wasted an entire day trying to figure out why my real method was being called when trying to setup a stub. See @MarcG comment. If the method you're trying to mock is marked final, you'll get NO error, NO warning, NOTHING. It just won't work and you're out of luck unless you're lucky enough to stumble on this comment or MarkG's... There's several reasons mockito will silently fail, but I'm betting loads of people show up here because their method is final and mockito fails silently. – MikeyT May 21 '20 at 20:38
  • Why is the when impossible in this example? – JobHunter69 Jun 19 '20 at 20:33
  • 3
    For everyone who got to this point, tried everything and Mokito still calling original method - look below for @ejaenv answer. – Timur Sadykov Oct 02 '20 at 10:39
  • as @TimurSadykov said, [this answer](https://stackoverflow.com/a/43103830/26510) may solve your problem if you got this far! – Brad Parks Nov 12 '20 at 16:30
  • Another possibility for why it might still call the real method is if you have an overloaded method and the parameters used when mocking don't match the overload you're trying to test. – rooby Aug 05 '22 at 03:43
  • I was missing ```@ExtendWith(MockitoExtension.class)``` which even after doing the above gave me an error argument passed to when is not a mock. – sriram Jun 27 '23 at 18:48
57

In my case, using Mockito 2.0, I had to change all the any() parameters to nullable() in order to stub the real call.

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
ejaenv
  • 2,117
  • 1
  • 23
  • 28
  • 9
    Don't let that 321 voted top answer get you down, this solved my problem :) I've been struggling with this for a couple hours! – Chris Kessel Nov 21 '17 at 15:55
  • 12
    This was the answer for me. To make it even easier for those that follow when mocking your method the syntax is: `foo = Mockito.spy(foo);` `Mockito.doReturn(someValue).when(foo).methodToPrevent(nullable(ArgumentType.class));` – Stryder Aug 24 '18 at 10:22
  • With Mockito 2.23.4 I can confirm this is not necessary, it works fine with `any` and `eq` matchers. – vmaldosan Feb 26 '19 at 11:24
  • 3
    Tried three different approached on 2.23.4 lib version: any(), eq() and nullable(). Only the later worked – ryzhman Apr 08 '19 at 20:36
  • Hi, your solution really nice and worked for me as well. Thanks – Dhiren Solanki Jun 10 '20 at 13:17
  • 3
    Im using mockito-core version 3.4.0 and making it `nullable()` worked. Can someone explain why `any()` doesnt work? – Boss Man Jul 21 '20 at 15:26
  • I had to change `anyString()` to `any()`. Mockito currently (3.4.0) stopped allowing the more specific matchers to match `null`, just like it stopped allowing `any()` to work with primitives _because_ it now passes null. Crazy stuff. – Matthew Read Oct 29 '20 at 15:26
  • 4
    But in the case of this post, there are no parameters – Wesley De Keirsmaeker Oct 20 '21 at 15:22
  • 1
    Any solution for the case when there are not parameters? It still doesn't work for me. My method is not final and not static – Yash Feb 21 '23 at 20:27
  • This helped when others didn't. Upvoted. – DanSoren May 01 '23 at 22:44
  • This answer deserves its own question :) – Ferran Maylinch Aug 31 '23 at 19:30
30

My case was different from the accepted answer. I was trying to mock a package-private method for an instance that did not live in that package

package common;

public class Animal {
  void packageProtected();
}

package instances;

class Dog extends Animal { }

and the test classes

package common;

public abstract class AnimalTest<T extends Animal> {
  @Before
  setup(){
    doNothing().when(getInstance()).packageProtected();
  }

  abstract T getInstance();
}

package instances;

class DogTest extends AnimalTest<Dog> {
  Dog getInstance(){
    return spy(new Dog());
  }

  @Test
  public void myTest(){}
}

The compilation is correct, but when it tries to setup the test, it invokes the real method instead.

Declaring the method protected or public fixes the issue, tho it's not a clean solution.

Maragues
  • 37,861
  • 14
  • 95
  • 96
  • 2
    I ran into a similar issue, but the test and package-private method were in the same package. I think perhaps Mockito has issues with package-private methods in general. – Dave May 11 '17 at 02:19
  • Is there any known fix for this now ? I am facing similar scenario as @Maragues . – Subhajit Sep 02 '21 at 16:24
22

The answer by Tomasz Nurkiewicz appears not to tell the whole story!

NB Mockito version: 1.10.19.

I am very much a Mockito newb, so can't explain the following behaviour: if there's an expert out there who can improve this answer, please feel free.

The method in question here, getContentStringValue, is NOT final and NOT static.

This line does call the original method getContentStringValue:

doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));

This line does not call the original method getContentStringValue:

doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));

For reasons which I can't answer, using isA() causes the intended (?) "do not call method" behaviour of doReturn to fail.

Let's look at the method signatures involved here: they are both static methods of Matchers. Both are said by the Javadoc to return null, which is a little difficult to get your head around in itself. Presumably the Class object passed as the parameter is examined but the result either never calculated or discarded. Given that null can stand for any class and that you are hoping for the mocked method not to be called, couldn't the signatures of isA( ... ) and any( ... ) just return null rather than a generic parameter* <T>?

Anyway:

public static <T> T isA(java.lang.Class<T> clazz)

public static <T> T any(java.lang.Class<T> clazz)

The API documentation does not give any clue about this. It also seems to say the need for such "do not call method" behaviour is "very rare". Personally I use this technique all the time: typically I find that mocking involves a few lines which "set the scene" ... followed by calling a method which then "plays out" the scene in the mock context which you have staged... and while you are setting up the scenery and the props the last thing you want is for the actors to enter stage left and start acting their hearts out...

But this is way beyond my pay grade... I invite explanations from any passing Mockito high priests...

* is "generic parameter" the right term?

mike rodent
  • 14,126
  • 11
  • 103
  • 157
  • 1
    I don't know if this adds clarity or further confuses the matter, but the difference between isA() and any() is that isA actually does type checking, whereas any() family of methods was created simply to avoid type casting of the argument. – Kevin Welker Nov 17 '16 at 00:05
  • @KevinWelker Thanks. And indeed the method names are not lacking in a certain self-explanatory quality. I do however, and however mildly, take issue with the genius Mockito designers for not documenting adequately. No doubt I need to read yet another book on Mockito. PS actually there seem to be very few resources to teach "intermediate Mockito"! – mike rodent Nov 20 '16 at 21:49
  • 1
    The history is that the anyXX methods were created first as a way to deal with typecasting only. Then when it was suggested they add the argument checking, they didn't want to break users of the existing API, so they created the isA() family. Knowing that the any() methods should have done the type checking all along, they delayed changing those until they introduced other breaking changes in the Mockito 2.X overhaul (which I have not tried yet). In 2.x+, anyX() methods are aliases for the isA() methods. – Kevin Welker Nov 23 '16 at 22:19
  • Thank you. This is a pivotal answer for those of us doing several library updates at the same time, because code that used to run is suddenly and silently failing. – Dex Stakker Jul 20 '18 at 21:42
19

One more possible scenario which may causing issues with spies is when you're testing spring beans (with spring test framework) or some other framework that is proxing your objects during test.

Example

@Autowired
private MonitoringDocumentsRepository repository

void test(){
    repository = Mockito.spy(repository)
    Mockito.doReturn(docs1, docs2)
            .when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}

In above code both Spring and Mockito will try to proxy your MonitoringDocumentsRepository object, but Spring will be first, which will cause real call of findMonitoringDocuments method. If we debug our code just after putting a spy on repository object it will look like this inside debugger:

repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$

@SpyBean to the rescue

If instead @Autowired annotation we use @SpyBean annotation, we will solve above problem, the SpyBean annotation will also inject repository object but it will be firstly proxied by Mockito and will look like this inside debugger

repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$

and here is the code:

@SpyBean
private MonitoringDocumentsRepository repository

void test(){
    Mockito.doReturn(docs1, docs2)
            .when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
Adrian Kapuscinski
  • 1,124
  • 12
  • 13
11

Important gotcha on spying real objects

When stubbing a method using spies , please use doReturn() family of methods.

when(Object) would result in calling the actual method that can throw exceptions.

List spy = spy(new LinkedList());

//Incorrect , spy.get() will throw IndexOutOfBoundsException   
 when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing    
doReturn("foo").when(spy).get(0);
Rakesh Soni
  • 10,135
  • 5
  • 44
  • 51
3

I've found yet another reason for spy to call the original method.

Someone had the idea to mock a final class, and found about MockMaker:

As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line: mock-maker-inline

Source: https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods

After I merged and brought that file to my machine, my tests failed.

I just had to remove the line (or the file), and spy() worked.

Matruskan
  • 325
  • 3
  • 11
  • this was the reason in my case, I was trying to mock a final method but it kept calling the real one without a clear error message which was confusing. – Bashar Ali Labadi Apr 15 '19 at 03:53
0

One way to make sure a method from a class is not called is to override the method with a dummy.

    WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
            @Override
            public void select(TreeItem i) {
                log.debug("SELECT");
            };
        });
0

As mentioned in some of the comments, my method was "static" (though being called on by an instance of the class)

public class A {
  static void myMethod() {...}
}
A instance = spy(new A());
verify(instance).myMethod(); // still calls the original method because it's static

Work around was make an instance method or upgrade Mockito to a newer version with some config: https://stackoverflow.com/a/62860455/32453

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
-1

Bit late to the party but above solutions did not work for me , so sharing my 0.02$

Mokcito version: 1.10.19

MyClass.java

private int handleAction(List<String> argList, String action)

Test.java

MyClass spy = PowerMockito.spy(new MyClass());

Following did NOT work for me (actual method was being called):

1.

doReturn(0).when(spy , "handleAction", ListUtils.EMPTY_LIST, new String());

2.

doReturn(0).when(spy , "handleAction", any(), anyString());

3.

doReturn(0).when(spy , "handleAction", null, null);

Following WORKED:

doReturn(0).when(spy , "handleAction", any(List.class), anyString());
tryingToLearn
  • 10,691
  • 12
  • 80
  • 114