Mockito - Fake Concrete Classes

Given the following code:

LinkedList list = mock(LinkedList.class); doCallRealMethod().when(list).clear(); list.clear(); 

by running this test, a NullPointerException is thrown from the first line in LinkedList # clear:

 public void clear() { Entry<E> e = header.next; while (e != header) { Entry<E> next = e.next; //Code omitted. 

but the header was created earlier:

 private transient Entry<E> header = new Entry<E>(null, null, null); 

Can anyone explain what happens during mock creation?

####### UPDATE. ######

After reading all the answers, especially Ajay one, I looked at the source code of Objenesis and found out that it uses the Reflection API to create a proxy instance (via CGLIB) and therefore bypasses all the constructors in the hierarchy to java.lang.Object.

Here is a sample code to model the problem:

 public class ReflectionConstructorTest { @Test public void testAgain() { try { //java.lang.Object default constructor Constructor javaLangObjectConstructor = Object.class .getConstructor((Class[]) null); Constructor mungedConstructor = ReflectionFactory .getReflectionFactory() .newConstructorForSerialization(CustomClient.class, javaLangObjectConstructor); mungedConstructor.setAccessible(true); //Creates new client instance without calling its constructor //Thus "name" is not initialized. Object client = mungedConstructor.newInstance((Object[]) null); //this will print "CustomClient" System.out.println(client.getClass()); //this will print "CustomClient: null". name is null. System.out.println(client.toString()); } catch(Exception e) { e.printStackTrace(); } } } class CustomClient { private String name; CustomClient() { System.out.println(this.getClass().getSimpleName() + " - Constructor"); this.name = "My Name"; } @Override public String toString() { return this.getClass().getSimpleName() + ": " + name; } } 
+7
source share
3 answers

Your reasoning is impeccable.
The main problem is that you are not working with the actual LinkedList object. Here's what happens behind the scenes:

The object you provided to Mockito mock() is an Enhancer object from the CGLIB library.

For me it is something like java.util.LinkedList$$EnhancerByMockitoWithCGLIB$$cae81a28

which acts as a proxy server, albeit with fields set to default values. (zero, 0, etc.)

+5
source

You only ask Mockito to name the real thing on a clear, the main object is still a fake, created by Mockito for you. If you need a real LinkedList, just use LinkedList - only the warmest BDD purist will tell you that you are mocking everything around. I mean, you're not kidding Strings, are you?

The author of Mockito himself said that calling the real thing should hardly be used, usually only for testing outdated code.

If you need to spy on a real object (track calls), then Mockito has a function for this:

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

With a spy, you can still drown out the method if you need to. It basically works like a layout, but is not;)

+7
source

When you mock a class, the object you are using is fake, so the variables are not created and the methods do not work properly. You can use reflection to set the value for the title, but I really would not recommend this. As theadam said, it would be best to just use a list.

+1
source

All Articles