【问题标题】:Testing Spring controllers using Powermock使用 Powermock 测试 Spring 控制器
【发布时间】:2013-02-19 20:49:11
【问题描述】:

我有一个测试特定控制器的类,它工作正常

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:config/test-applicationContext-config.xml")
@TestExecutionListeners({ 
    WebContextTestExecutionListener.class, 
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class })
public class TestAdminController {  
     //.....
}

我在那里使用了来自 mockito.org 的 Google 的 Mockito 库来模拟我的底层 bean。

现在我的问题如下:我有一些类也需要模拟,但它们有 final 方法,谷歌的模拟似乎无法解决这个问题。我的一位同事建议使用来自powermock.org 的 Powermock。但它需要使用@RunWith(PowerMockRunner.class) 注释来注释测试器类。如果我使用它,我必须删除注释@RunWith(SpringJUnit4ClassRunner.class),这会给我带来问题,因为不会创建 Spring 测试上下文。我怎样才能避免这种情况?

根据建议,我已配置为使用 PowerMockRule 而不是 @RunWith 注释

我的项目Maven依赖如下

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-mockito-release-full</artifactId>
    <version>1.5</version>
    <type>pom</type>
</dependency> 
<dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4-rule</artifactId>
        <version>1.5</version>
        <scope>test</scope>
</dependency>
<dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-classloading-xstream</artifactId>
        <version>1.5</version>
        <scope>test</scope>
</dependency>

现在我的班级看起来像这样(另一个控制器测试)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:config/test-applicationContext-config.xml")
@TestExecutionListeners({ 
    WebContextTestExecutionListener.class, 
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class })
@PrepareForTest(ADSynchronizationImpl.class)
public class ThirdPartyLoginControllerTest {
    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Autowired
    private ThirdPartyLoginController thirtPartyLoginController;

    @Autowired
    private MockFactoryForControllers mockFactory;

    @Test
    public void testLoginActiveDirectory(){

    }
}

但是在运行我的测试后,我得到了以下异常跟踪

com.thoughtworks.xstream.converters.ConversionException: javassist.NotFoundException: com.somecompany.analytics.manager.db.api.MlDao$$EnhancerByMockitoWithCGLIB$$b86d7415 : javassist.NotFoundException: com.somecompany.analytics.manager.db.api.MlDao$$EnhancerByMockitoWithCGLIB$$b86d7415 ----调试信息----消息:javassist.NotFoundException: com.somecompany.analytics.manager.db.api.MlDao$$EnhancerByMockitoWithCGLIB$$b86d7415 原因异常:java.lang.RuntimeException 原因消息: javassist.NotFoundException: com.somecompany.analytics.manager.db.api.MlDao$$EnhancerByMockitoWithCGLIB$$b86d7415 班级 : com.somecompany.ui.controllers.ThirdPartyLoginController 所需类型 : com.somecompany.ui.controllers.ThirdPartyLoginController 转换器类型: com.thoughtworks.xstream.converters.reflection.ReflectionConverter 小路 : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/fTarget/thirtPartyLoginController/mlDao 行号:14 类1: com.somecompany.ui.controllers.ThirdPartyLoginControllerTest class2 : org.junit.internal.runners.statements.InvokeMethod 类[3]
: org.powermock.modules.junit4.rule.PowerMockStatement 类[4]
: org.powermock.modules.junit4.rule.PowerMockStatement$1 版本
: 空值 ------------------------------------------- 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) 在 com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) 在 com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) 在 com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) 在 com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:355) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:306) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) 在 com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) 在 com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) 在 com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1052) 在 com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1036) 在 com.thoughtworks.xstream.XStream.fromXML(XStream.java:912) 在 com.thoughtworks.xstream.XStream.fromXML(XStream.java:903) 在 org.powermock.classloading.DeepCloner.clone(DeepCloner.java:54) 在 org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:89) 在 org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78) 在 org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:49) 在 org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 在 org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) 在 org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 在 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 在 org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 在 org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:309) 在 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 引起:java.lang.RuntimeException:javassist.NotFoundException: com.somecompany.idm.analytics.manager.db.api.MlDao$$EnhancerByMockitoWithCGLIB$$b86d7415 在 org.powermock.core.classloader.MockClassLoader.loadUnmockedClass(MockClassLoader.java:199) 在 org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:149) 在 org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:356) 在 com.thoughtworks.xstream.core.util.ClassLoaderReference.loadClass(ClassLoaderReference.java:31) 在 com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:49) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:55) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:79) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:74) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:30) 在 com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:45) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.determineType(AbstractReflectionConverter.java:458) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:294) 在 com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234) 在 com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) ... 57 更多原因:javassist.NotFoundException: com.somecompany.analytics.manager.db.api.MlDao$$EnhancerByMockitoWithCGLIB$$b86d7415 在 javassist.ClassPool.get(ClassPool.java:450) 在 org.powermock.core.classloader.MockClassLoader.loadUnmockedClass(MockClassLoader.java:192) ... 87 更多

【问题讨论】:

    标签: java spring-mvc mockito powermock spring-test-mvc


    【解决方案1】:

    查看this article,它解释了如何使用 PowerMock 和SpringJUnit4ClassRunner。基本上,你只需要使用special PowerMockRule rule:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:config/test-applicationContext-config.xml")
    @TestExecutionListeners({ 
        WebContextTestExecutionListener.class, 
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class })
    public class SpringExampleTest {
    
        @Rule
        public PowerMockRule rule = new PowerMockRule();
    
    }
    

    编辑:似乎other people had the same problem 与您对@PowerMockRule 一样。改用 PowerMockAgent 可以解决您的问题。另请参阅 SO 上的 this anwer

    【讨论】:

    • 我已经试过了,但是powermock下的X-Stream库似乎很容易出现错误,这也在你发布的文章中说
    • 其实文章说 XStream 比 Objenesis 更健壮,他们提到的 bug 似乎出现在 Objenesis 中。我在其他项目中使用过 XStream(不是使用 PowerMock),从来没有遇到过任何问题。你遇到过这样的bug吗?
    • 感谢您的建议,与spring一起使用后出现错误。我已将帖子编辑得更清楚
    • 你能看看你的类路径中是否有多个版本的 Mockito 吗?当两个不同的类加载器加载相同依赖项的两个不同版本时,通常会发生此类错误。 mvn dependency:tree 可以帮你解决这个问题。
    • 是的,似乎我在类路径上有多个版本。但是在修复之后,我又遇到了另一个错误。我已更改异常跟踪
    【解决方案2】:

    您也可以尝试使用注释您的测试类

    @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
    

    参见示例here

    【讨论】:

    • 另外,在委托部分之前添加@RunWith(PowerMockRunner.class)
    • 示例死链接
    • @jpmottin 尝试查看以前的版本,我可以 find 这个文件获取 1.6.0 标签。
    • 谢谢@gce?你能更新原始消息中提供的链接吗?
    【解决方案3】:

    您可以使用 JMockit 代替 Powermock。它可以做 Powermock 可以做的所有事情,而且它不需要 @RunWith 子句,因此它不会干扰您的 Spring 测试运行器。我发现 PowerMockRule 引入的问题比它解决的要多...

    【讨论】:

    • 谢谢你的建议,我试试这个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多