Search code examples
log4jpowermockpowermockitopitestpowermockrunner

Mutation Test Coverage fails when mock static method


I'm trying to get the mutation coverage of unit test but getting weird exception from pitest:

    7:55:09 PM PIT >> INFO : MINION : 7:55:09 PM PIT >> SEVERE : Error calculating coverage. Process will exit.
java.lang.ExceptionInInitializerError
    at org.apache.log4j.LogManager.<clinit>(LogManager.java:82)
    at org.apache.log4j.Logger.getLogger(Logger.java:117)
    at sample.ClassWithStat
7:55:09 PM PIT >> INFO : MINION : icField.<clinit>(ClassWithStaticField.java:9)
    at sun.reflect.GeneratedSerializationConstructorAccessor17.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.objenesis.instantiator.sun.SunReflectionFac
7:55:09 PM PIT >> INFO : MINION : toryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
    at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
    at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14)
    at org
7:55:09 PM PIT >> INFO : MINION : .powermock.api.mockito.repackaged.ClassImposterizer.createProxy(ClassImposterizer.java:143)
    at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:58)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.
7:55:09 PM PIT >> INFO : MINION : createMethodInvocationControl(MockCreator.java:111)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:59)
    at org.powermock.api.mockito.PowerMockito.mock(PowerMockito.java:203)
    at org.powermock.api.extension.listener
7:55:09 PM PIT >> INFO : MINION : .AnnotationEnabler.standardInject(AnnotationEnabler.java:106)
    at org.powermock.api.extension.listener.AnnotationEnabler.beforeTestMethod(AnnotationEnabler.java:54)
    at org.powermock.tests.utils.impl.PowerMockTestNotifierImpl.notifyBeforeTestMethod(Power
7:55:09 PM PIT >> INFO : MINION : MockTestNotifierImpl.java:90)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:292)
    at org.powermock.modules.junit4.internal.impl.PowerMock
7:55:09 PM PIT >> INFO : MINION : JUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUni
7:55:09 PM PIT >> INFO : MINION : t47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodR
7:55:09 PM PIT >> INFO : MINION : oadie.runTest(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at
7:55:09 PM PIT >> INFO : MINION :  org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateIm
7:55:09 PM PIT >> INFO : MINION : pl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.ru
7:55:09 PM PIT >> INFO : MINION : n(PowerMockJUnit44RunnerDelegateImpl.java:122)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.r
7:55:09 PM PIT >> INFO : MINION : un(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at org.pitest.junit.adapter.CustomRunnerExecutor.run(CustomRunnerExecutor.java:42)
    at org.pitest.junit.adapter.AdaptedJUnitTestUnit
7:55:09 PM PIT >> INFO : MINION : .execute(AdaptedJUnitTestUnit.java:69)
    at org.pitest.coverage.execute.CoverageDecorator.execute(CoverageDecorator.java:49)
    at org.pitest.testapi.execute.containers.UnContainer.execute(UnContainer.java:31)
    at org.pitest.testapi.execute.Pitest.executeT
7:55:09 PM PIT >> INFO : MINION : ests(Pitest.java:57)
    at org.pitest.testapi.execute.Pitest.run(Pitest.java:48)
    at org.pitest.coverage.execute.CoverageWorker.run(CoverageWorker.java:49)
    at org.pitest.coverage.execute.CoverageMinion.main(CoverageMinion.java:90)
Caused by: java.lang.N
7:55:09 PM PIT >> INFO : MINION : ullPointerException
    at org.apache.log4j.Level.<init>(Level.java)
    at org.apache.log4j.Priority.<clinit>(Priority.java:45)
    ... 39 more

7:55:09 PM PIT >> SEVERE : Coverage generator Minion exited abnormally due to UNKNOWN_ERROR

Here is the test:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({ClassWithStaticField.class})
    public class DemoClassTest {
    
      @Mock
      private ClassWithStaticField mock;
    
      @Before
      public void setUp() {
        PowerMockito.mockStatic(ClassWithStaticField.class);
        PowerMockito.when(ClassWithStaticField.getInstance()).thenReturn(mock);
      }
    
      @Test
      public void test() {
        List<String> testData = Collections.singletonList("test data");
        when(mock.getData()).thenReturn(testData);
    
        DemoClass demoClass = new DemoClass();
        Map<String, List<String>> map = demoClass.getMap();
    
        Assert.assertNotNull(map);
        Assert.assertEquals(testData, map.get("key"));
      }
    }

Class under test:

    public class DemoClass {
    
      public Map<String, List<String>> getMap() {
        ClassWithStaticField instance = ClassWithStaticField.getInstance();
        List<String> data = instance.getData();
        return Collections.singletonMap("key", data);
      }
    
    }

Singleton:

    public class ClassWithStaticField {
    
      private static final Logger LOGGER = Logger.getLogger(ClassWithStaticField.class);
    
      public ClassWithStaticField() { }
    
      private static class LazyHolder {
        private static final ClassWithStaticField INSTANCE = new ClassWithStaticField();
      }
    
      public static ClassWithStaticField getInstance() {
        LOGGER.info("Producing instance");
        return LazyHolder.INSTANCE;
      }
    
      public List<String> getData() {
        LOGGER.info("getting data from db...");
        return Collections.singletonList("Dummy data");
      }
    }

It looks like static logger field is causing the issue when PowerMock makes an attempt to instantiate it but I am not sure why. I would appreciate it if someone could help me to find the reason behind this issue.

Libraries used:

junit:junit:4.12
org.powermock:powermock-api-mockito:1.6.4
org.powermock:powermock-module-junit4:1.6.4
org.pitest:pitest-maven:1.5.2:

Solution

  • I was able to solve this problem by adding the following annotation to the test class:

    @PowerMockIgnore({"org.apache.log4j.*"})
    

    After that exception has gone.