Using PowerMock to mock static properties with @InjectMocks

I use PowerMock and Mockito to test the Spring controller.

I have defined the TestController class (see below, Snipper # 1) and the Unit Test defined for it (see below, Snipper # 2). But when I try Unit Test, I get an exception (see below, Snipper # 3).

If I delete @InjectMocks, delete the TestController instance in the definition, and execute controllerUT = new TestController () in the test function, it works fine (see below, Snipper # 4).

This makes me think that static replacement does not happen before @InjectMocks, and my question is how it works, or am I doing something wrong? Is there a better way to develop code to avoid this problem? I assume that people use the static assignment of logs (I did not invent this), so someone should have encountered this problem before ...

Thanks!

Fragment # 1

@Controller @RequestMapping("/api/test") public class TestController { private static final Logger LOG = LoggerFactory.getLogger(TestController.class); @Autowired private GeneralService generalService; @RequestMapping(method=RequestMethod.GET) public void doSomethingUseful( HttpServletRequest request, HttpServletResponse response) { // nothing userful to do right now } } 

Fragment # 2

 @RunWith(PowerMockRunner.class) @PrepareForTest({TestController.class, LoggerFactory.class}) public class TestControllerTest { @InjectMocks private TestController controllerUT = new TestController(); @Mock private GeneralService service; @Mock private Logger loggerMock; @Mock private HttpServletRequest request; @Mock private HttpServletResponse response; @Before public void setUp() { PowerMockito.mockStatic(LoggerFactory.class); when(LoggerFactory.getLogger(any(Class.class))). thenReturn(loggerMock); } @Test public void doSomethingUsefulTest() { controllerUT.doSomethingUseful(request, response); assert(true); } } 

Fragment # 3

 Failed to auto configure default logger context Reported exception: ch.qos.logback.core.joran.spi.JoranException: Parser configuration error occurred at ch.qos.logback.core.joran.event.SaxEventRecorder.buildSaxParser(SaxEventRecorder.java:86) at ch.qos.logback.core.joran.event.SaxEventRecorder.recordEvents(SaxEventRecorder.java:57) at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:132) at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:96) at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:55) at ch.qos.logback.classic.util.ContextInitializer.configureByResource(ContextInitializer.java:75) at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:148) at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:84) at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:54) at org.slf4j.LoggerFactory.bind(LoggerFactory.java:128) at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:108) at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:279) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:252) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:265) at com.basicservice.controller.TestController.<clinit>(TestController.java:39) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:169) at javassist.runtime.Desc.getClassObject(Desc.java:43) at javassist.runtime.Desc.getClassType(Desc.java:152) at javassist.runtime.Desc.getType(Desc.java:122) at javassist.runtime.Desc.getType(Desc.java:78) at com.basicservice.controller.TestControllerTest.<init>(TestControllerTest.java:44) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.createTestInstance(PowerMockJUnit44RunnerDelegateImpl.java:188) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.createTest(PowerMockJUnit44RunnerDelegateImpl.java:173) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:195) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 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.run(PowerMockJUnit44RunnerDelegateImpl.java:120) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102) at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:42) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.lang.ClassCastException: org.apache.xerces.jaxp.SAXParserFactoryImpl cannot be cast to javax.xml.parsers.SAXParserFactory at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:128) at ch.qos.logback.core.joran.event.SaxEventRecorder.buildSaxParser(SaxEventRecorder.java:79) ... 42 more 

Fragment # 4

 @RunWith(PowerMockRunner.class) @PrepareForTest({TestController.class, LoggerFactory.class}) public class TestControllerTest { private TestController controllerUT; @Mock private GeneralService service; @Mock private Logger loggerMock; @Mock private HttpServletRequest request; @Mock private HttpServletResponse response; @Before public void setUp() { PowerMockito.mockStatic(LoggerFactory.class); when(LoggerFactory.getLogger(any(Class.class))). thenReturn(loggerMock); } @Test public void doSomethingUsefulTest() { controllerUT = new TestController(); controllerUT.doSomethingUseful(request, response); assert(true); } } 
+4
source share
1 answer

It should be remembered that @InjectMocks complies with static and trailing fields, that is, it does not introduce mocks in static or trailing fields. Also note that PowerMock should spawn a new ClassLoader for “instrumental” classes, which probably explains snippet # 3.

While I have not studied your projects, I believe that you may need to prepare all the Logback / slf4j classes if you want to use PowerMock. Keep in mind that Powermock and Mockito are separate projects and may not work together as you might think.

+1
source

Source: https://habr.com/ru/post/1441654/


All Articles