How does mockito work when () called?

Given the following Mockito expression:

when(mock.method()).thenReturn(someValue); 

How is Mockito going to create a proxy server for the layout, given that the mock.method () statement passes the return value when ()? I suppose this uses some CGLib stuff, but it would be interesting to know how it is technically done.

+68
unit-testing mockito mocking
Jan 21 '13 at 2:00
source share
2 answers

The short answer is that in your example, the result of mock.method() will be an empty value corresponding to the type; mockito uses indirect proxy passing, an interception method, and a common instance of the MockingProgress class to determine if the method call to the layout is to nullify or repeat the existing shaded behavior, and not pass stubbing execution information through the return value of the mocking method.

A mini analysis after a couple of minutes, looking at the mockito code, looks like this. Note that this is a very crude description - there are many details. I suggest you check the source on github yourself.

First, when you mock a class using the Mockito class mock method, this essentially happens:

  • Mockito.mock delegates to org.mockito.internal.MockitoCore .mock, passing the default layout settings as a parameter.
  • MockitoCore.mock delegates to org.mockito.internal.util.MockUtil .createMock
  • The MockUtil class uses the ClassPathLoader class to get the MockMaker instance to use for creating the layout. The default class is CgLibMockMaker .
  • CgLibMockMaker uses a class borrowed from JMock, ClassImposterizer , which handles layout creation. The key elements of mockito magic are the MethodInterceptor used to create the layout: the mockito MethodInterceptorFilter and the chain of MockHandler instances, including the MockHandlerImpl instance. The interceptor method passes calls to an instance of MockHandlerImpl, which implements the business logic that should be applied when calling the method on the layout (i.e., Search to check if the response has already been recorded, determining whether the call is a new stub, etc. default: if the stub has not yet been registered for the called method, the return value of the type is returned.

Now look at the code in your example:

 when(mock.method()).thenReturn(someValue) 

Here is the execution order of this code:

  • mock.method()
  • when(<result of step 1>)
  • <result of step 2>.thenReturn

The key to understanding what is happening is what happens when the method is called on mock: the method interceptor passes information about the method call and delegates it to the chain of MockHandler instances, which are ultimately delegated to MockHandlerImpl#handle . During MockHandlerImpl#handle the mock handler creates an instance of OngoingStubbingImpl and passes it to the shared instance of MockingProgress .

When the when method is called after calling method() , it delegates to MockitoCore.when , which calls the stub() method of the same class. This method decompresses the current termination from a common instance of MockingProgress , into which a laughed call to method() called and returns it. Then, the OngoingStubbing method is called on the thenReturn .

+77
Jan 21
source share

The short answer, behind the scenes, Mockito uses some kind of global variables / storage to store information about the steps of constructing the method stub (calling the method () when (), thenReturn () in your example), so that it can eventually create a map of what should be returned when which parameter is called.

I found this article very useful: An explanation of how the Mock Frameworks proxy-based servers work ( http://blog.rseiler.at/2014/06/explanation-how-proxy-based-mock.html ). The author implemented the Mocking demo framework, which I found a very good resource for people who want to understand how these Mocking frameworks work.

In my opinion, this is a typical use of Anti-Pattern. Usually we should avoid the “side effect” when we implement the method, that is, the method must accept the input and perform some calculations and return the result - nothing else has changed. But Mokito simply violates this rule on purpose. Its methods store a lot of information, and also return the result: Mockito.anyString (), mockInstance.method (), when (), thenReturn, they all have a special "side effect". This is why the structure looks like magic at first sight - we usually do not write such code. However, in the mocking wireframe case, this anti-template design is a great design because it leads to a very simple API.

+12
Aug 31 '15 at 22:46
source share



All Articles