首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用PowerMock模拟@InjectMocks的静态属性

使用PowerMock模拟@InjectMocks的静态属性
EN

Stack Overflow用户
提问于 2012-10-23 20:47:38
回答 1查看 5.1K关注 0票数 4

我使用PowerMock和Mockito来测试Spring控制器。

我定义了类TestController (参见下面,狙击手#1),并为其定义了一个单元测试(参见下面的Sniper2)。但是当我尝试对它进行单元测试时,我会得到一个异常(参见下面的Snipper #3)。

如果我删除@InjectMocks,删除定义上的TestController实例化,并在测试函数中执行controllerUT =(),它可以很好地工作(参见下面,狙击手#4)。

这让我相信,静态替换不会发生在@InjectMocks之前,我的问题是这是事情的工作方式,还是我做错了什么?是否有更好的方法来设计代码以避免这个问题?我猜人们使用静态日志分配(这不是我发明的),所以一定有人在此之前遇到过这个问题。

谢谢!

片段#1

代码语言:javascript
运行
复制
@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
    }
}

代码片段#2

代码语言:javascript
运行
复制
@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);
    }
}

代码片段#3

代码语言:javascript
运行
复制
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

代码片段#4

代码语言:javascript
运行
复制
@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);
    }
}
EN

回答 1

Stack Overflow用户

发布于 2012-10-23 23:22:43

需要记住的一点是,@InjectMocks尊重静态和最终字段,即它不会在静态或最终字段中注入模拟。还请注意,PowerMock必须生成一个新的ClassLoader才能“检测”类,这可能解释了代码片段#3。

虽然我没有探究您的项目的来龙去脉,但如果您想使用PowerMock,我相信您可能希望准备所有的Logback/slf4j类。请记住,Powermock和Mockito是不同的项目,可能不会像人们想象的那样一起工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13038976

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档