Search code examples
javapowermockito

PowerMockito - Spying - Real method called


Extending - https://stackoverflow.com/a/29394497/1260692 (as stackoverflow doesn't allow me to comment without 50 reputation)

Why does a real method is called on spies during mock setup in when/then style?

I see that org.powermock.api.mockito.internal.expectation.DefaultMethodExpectationSetup (Mockito version 1.5.6) calls the actual method in line numbers - 44, 46 and 52. Can some Mockito expert explain why is this happening and how to avoid this?

FYI, when I switch to doReturn/when style, no issues. Test runs as expected.


Solution

  • Without knowing the ins and outs of PowerMock, but calling when(foo.method())... is executed using the usual Java semantics: first the method call foo.method(), then the rest using the result of the call. Now, foo is a mocked object at that time, created by PowerMock. It is not empty but has a whole bunch of logic that records calls. This mock object records the call to method(). Then the when() method call is executed and queries the mock object that is currently being stubbed about which method was called last and with which parameters. This information is used to configure the stubbed return value.

    Mockito's API looks like magic, but it is just a very cleverly designed API with a ton of totally normal Java code to get it working. :-)

    Edit:

    Explained in other words: in when(foo.method()), foo is a mock object that has a method method() whose code has nothing to do with that of the original object, but deals with recording calls to the method. So, since this is, after all, plain Java, first foo.method() is executed. It returns some arbitrary value according to the interface of the original method signature (e.g. an int when method() would usually return an int). To get the information to Mockito, that you're about to stub foo.method(), the mock objects communicates to Mockito "dude, I just got called". Methods with parameters also communicate the parameters they were called with to Mockito. So, Mockito's when() memorize that call and returns an object with a thenReturn() method. Before this is called, its parameter is evaluated. The value is then passed to the thenReturn() method, which communicates to Mockio "dude, when asked, return this". Mockito knows it's in the process of stubbing a call to foo.method() and connects the return value internally to the call. So later, when the mock is called using the foo.method(), it looks up the return value and returns it.

    I kind of doubt that the other way of expressing this (doReturn().when()) works fundamentally differently.