GhostCat GhostCat - 25 days ago 8
Java Question

How to prevent creation of mock objects to run static inits?

Given this code:

class Booh {
final static Booh throwUp = new Booh();
Booh() { throw new RuntimeException("I didn't see that one coming"); }
}


And a test using Mokito.mock():

@Test
public void testBooh() {
Booh booh;
booh = mock(Booh.class);
}
}


I end up with:


java.lang.ExceptionInInitializerError
at java.lang.J9VMInternals.ensureError(J9VMInternals.java:137)
at java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:126)
at sun.reflect.GeneratedSerializationConstructorAccessor12.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:436)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:56)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxy(ClassImposterizer.java:128)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:63)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at my.test.Class.testBooh(my.test.Class.java:162)
....


Caused by: java.lang.RuntimeException: I didn't see that one coming
...

Simple question: are there any means how I could prevent that exception; without changing the production code to avoid that static init thing?

( the above code is a mcve; in reality, things are more complicated, but in the end our problem is that unit test code tries to mock a class ... and that causes a ton of static finals to be init'ed; and some those init statements throws up in our unit test environment).

For the record: this is not a Mokito problem, I run into the same issue using EasyMock for example.

Answer

One solution is to mock the class with JMockit:

@Test
public void testBooh(@Mocked(stubOutClassInitialization = true) Booh booh) {
    ...
}

(By default, stubOutClassInitialization is false because stubbing out the static initializers of a class means any static final fields will remain uninitialized until the end of the test run, as the JVM only performs static initialization once per loaded class.)

Apart from that, you would either have to use some other bytecode manipulation tool (AspectJ, JBoss AOP, JBoss Byteman) or fix the actual production class which is failing during static initialization.