使用带有 Jersey Test + TestNg 的 powermock 测试 Jersey 休息服务时的问题
Issue when test a Jersey rest service using powermock with Jersey Test + TestNg
开发了一个使用Jersey的休息服务。现在我想为此 Web 服务编写一些集成测试,但由于并非 Web 服务中使用的每个 class 都已经实现,我需要模拟其中的一些。例如我有以下 class:
public class ServiceA {
public String getService() {
return null;
}}
@Path("/myresource")
public class ResourceController {
@GET
@Produces("text/plain")
public String getIt() {
ServiceA a = new ServiceA();
return a.getService();
}}
然后我想用 Jersey 测试框架和 TestNg + Powermock(使用构造函数模拟新对象)进行集成测试。
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTestNg;
import org.glassfish.jersey.test.jdkhttp.JdkHttpServerTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockObjectFactory;
import org.testng.Assert;
import org.testng.IObjectFactory;
import org.testng.annotations.ObjectFactory;
import org.testng.annotations.Test;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import static org.powermock.api.mockito.PowerMockito.mock;
@PowerMockIgnore({"javax.ws.*", "org.glassfish.*"})
@PrepareForTest({ResourceController.class})
public class ResourceControllerTest extends JerseyTestNg.ContainerPerMethodTest {
@Override
protected Application configure() {
return new ResourceConfig(ResourceController.class);
}
@Override
protected TestContainerFactory getTestContainerFactory() {
return new JdkHttpServerTestContainerFactory();
}
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test
public void getItTest() {
ServiceA mockA = mock(ServiceA.class);
Mockito.when(mockA.getService()).thenReturn("service a");
PowerMockito.whenNew(ServiceA.class).withAnyArguments().thenReturn(mockA);
Response result = target("myresource").request().get();
Assert.assertEquals(result.readEntity(String.class), "service a");
}
}
我的 pom 依赖项:
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-inmemory</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
但是在运行时,getIt() 方法中的实例 ServiceA 仍然被初始化为新的 ServiceA 对象,而不是 mockA 对象。
有什么想法吗?谢谢,
如果添加 PowerMockIgnore({"javax.ws.", "org.glassfish."}),则见以下异常:
java.lang.ExceptionInInitializerError
at org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter.<init>(ConditionalStackTraceFilter.java:17)
at org.mockito.exceptions.base.MockitoException.filterStackTrace(MockitoException.java:41)
at org.mockito.exceptions.base.MockitoException.<init>(MockitoException.java:30)
at org.mockito.exceptions.misusing.MockitoConfigurationException.<init>(MockitoConfigurationException.java:18)
at org.mockito.internal.configuration.plugins.PluginLoader.loadImpl(PluginLoader.java:66)
at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:24)
at org.mockito.internal.configuration.plugins.PluginRegistry.<init>(PluginRegistry.java:12)
at org.mockito.internal.configuration.plugins.Plugins.<clinit>(Plugins.java:11)
at org.mockito.internal.util.MockUtil.<clinit>(MockUtil.java:24)
at org.mockito.internal.configuration.injection.scanner.MockScanner.<init>(MockScanner.java:22)
at org.mockito.internal.configuration.InjectingAnnotationEngine.injectMocks(InjectingAnnotationEngine.java:96)
at org.powermock.api.mockito.internal.configuration.PowerMockitoInjectingAnnotationEngine.process(PowerMockitoInjectingAnnotationEngine.java:35)
at org.powermock.api.extension.listener.AnnotationEnabler.injectSpiesAndInjectToSetters(AnnotationEnabler.java:72)
at org.powermock.api.extension.listener.AnnotationEnabler.beforeTestMethod(AnnotationEnabler.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1846)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:700)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:415)
at org.powermock.modules.testng.internal.PowerMockTestNGMethodHandler.injectMocksUsingAnnotationEnabler(PowerMockTestNGMethodHandler.java:76)
at org.powermock.modules.testng.internal.PowerMockTestNGMethodHandler.invoke(PowerMockTestNGMethodHandler.java:48)
at com.hp.ucmdb.rest.ResourceControllerTest_$$_jvstb11_0.setUp(ResourceControllerTest_$$_jvstb11_0.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:514)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:215)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:589)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:127)
Caused by: java.lang.NullPointerException
at org.mockito.internal.configuration.plugins.Plugins.getStackTraceCleanerProvider(Plugins.java:17)
at org.mockito.internal.exceptions.stacktrace.StackTraceFilter.<clinit>(StackTraceFilter.java:21)
... 49 more
我相信模拟可能不会发生,因为您没有将 PowerMock 的对象工厂实现连接到 TestNG。
为了让 powermockito 和 TestNG 相互协作,您必须执行以下操作:
- 配置 TestNG 以使用 PowerMock 对象工厂:您可以通过套件 xml 的
<suite>
标签中的属性 object-factory
或通过 @org.testng.annotations.ObjectFactory
注释方法,其中 returns powermock 的 TestNG 接口实现 org.testng.IObjectFactory
即,org.powermock.modules.testng.PowerMockObjectFactory
(或)通过扩展 org.powermock.modules.testng.PowerMockTestCase
- 使用@PrepareForTest 准备静态 class 以供 PowerMockit
模拟
我无法在您的代码中使用 PowerMock 的对象工厂接线找到任何对您的引用。你能试试看是否有帮助吗?
请参阅 了解完整详情。
更新:
为了通过 ClassCastExceptions,您需要将以下注释添加到您的 class.
@org.powermock.core.classloader.annotations.PowerMockIgnore({"javax.ws.*", "org.glassfish.*"})
有关此的更多详细信息,请参阅this Whosebug问题
PS :我假设您正在使用以下注释让 powermock 准备您的测试 class 以进行模拟(您问题中的示例显示了其他内容)
@org.powermock.core.classloader.annotations.PrepareForTest({ResourceController.class})
开发了一个使用Jersey的休息服务。现在我想为此 Web 服务编写一些集成测试,但由于并非 Web 服务中使用的每个 class 都已经实现,我需要模拟其中的一些。例如我有以下 class:
public class ServiceA {
public String getService() {
return null;
}}
@Path("/myresource")
public class ResourceController {
@GET
@Produces("text/plain")
public String getIt() {
ServiceA a = new ServiceA();
return a.getService();
}}
然后我想用 Jersey 测试框架和 TestNg + Powermock(使用构造函数模拟新对象)进行集成测试。
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTestNg;
import org.glassfish.jersey.test.jdkhttp.JdkHttpServerTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockObjectFactory;
import org.testng.Assert;
import org.testng.IObjectFactory;
import org.testng.annotations.ObjectFactory;
import org.testng.annotations.Test;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Response;
import static org.powermock.api.mockito.PowerMockito.mock;
@PowerMockIgnore({"javax.ws.*", "org.glassfish.*"})
@PrepareForTest({ResourceController.class})
public class ResourceControllerTest extends JerseyTestNg.ContainerPerMethodTest {
@Override
protected Application configure() {
return new ResourceConfig(ResourceController.class);
}
@Override
protected TestContainerFactory getTestContainerFactory() {
return new JdkHttpServerTestContainerFactory();
}
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
@Test
public void getItTest() {
ServiceA mockA = mock(ServiceA.class);
Mockito.when(mockA.getService()).thenReturn("service a");
PowerMockito.whenNew(ServiceA.class).withAnyArguments().thenReturn(mockA);
Response result = target("myresource").request().get();
Assert.assertEquals(result.readEntity(String.class), "service a");
}
}
我的 pom 依赖项:
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-inmemory</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.21</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
但是在运行时,getIt() 方法中的实例 ServiceA 仍然被初始化为新的 ServiceA 对象,而不是 mockA 对象。
有什么想法吗?谢谢,
如果添加 PowerMockIgnore({"javax.ws.", "org.glassfish."}),则见以下异常:
java.lang.ExceptionInInitializerError
at org.mockito.internal.exceptions.stacktrace.ConditionalStackTraceFilter.<init>(ConditionalStackTraceFilter.java:17)
at org.mockito.exceptions.base.MockitoException.filterStackTrace(MockitoException.java:41)
at org.mockito.exceptions.base.MockitoException.<init>(MockitoException.java:30)
at org.mockito.exceptions.misusing.MockitoConfigurationException.<init>(MockitoConfigurationException.java:18)
at org.mockito.internal.configuration.plugins.PluginLoader.loadImpl(PluginLoader.java:66)
at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:24)
at org.mockito.internal.configuration.plugins.PluginRegistry.<init>(PluginRegistry.java:12)
at org.mockito.internal.configuration.plugins.Plugins.<clinit>(Plugins.java:11)
at org.mockito.internal.util.MockUtil.<clinit>(MockUtil.java:24)
at org.mockito.internal.configuration.injection.scanner.MockScanner.<init>(MockScanner.java:22)
at org.mockito.internal.configuration.InjectingAnnotationEngine.injectMocks(InjectingAnnotationEngine.java:96)
at org.powermock.api.mockito.internal.configuration.PowerMockitoInjectingAnnotationEngine.process(PowerMockitoInjectingAnnotationEngine.java:35)
at org.powermock.api.extension.listener.AnnotationEnabler.injectSpiesAndInjectToSetters(AnnotationEnabler.java:72)
at org.powermock.api.extension.listener.AnnotationEnabler.beforeTestMethod(AnnotationEnabler.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1846)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:700)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:415)
at org.powermock.modules.testng.internal.PowerMockTestNGMethodHandler.injectMocksUsingAnnotationEnabler(PowerMockTestNGMethodHandler.java:76)
at org.powermock.modules.testng.internal.PowerMockTestNGMethodHandler.invoke(PowerMockTestNGMethodHandler.java:48)
at com.hp.ucmdb.rest.ResourceControllerTest_$$_jvstb11_0.setUp(ResourceControllerTest_$$_jvstb11_0.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:86)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:514)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:215)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:589)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:820)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1128)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at org.testng.TestRunner.privateRun(TestRunner.java:782)
at org.testng.TestRunner.run(TestRunner.java:632)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:366)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319)
at org.testng.SuiteRunner.run(SuiteRunner.java:268)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1244)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1169)
at org.testng.TestNG.run(TestNG.java:1064)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:127)
Caused by: java.lang.NullPointerException
at org.mockito.internal.configuration.plugins.Plugins.getStackTraceCleanerProvider(Plugins.java:17)
at org.mockito.internal.exceptions.stacktrace.StackTraceFilter.<clinit>(StackTraceFilter.java:21)
... 49 more
我相信模拟可能不会发生,因为您没有将 PowerMock 的对象工厂实现连接到 TestNG。
为了让 powermockito 和 TestNG 相互协作,您必须执行以下操作:
- 配置 TestNG 以使用 PowerMock 对象工厂:您可以通过套件 xml 的
<suite>
标签中的属性object-factory
或通过@org.testng.annotations.ObjectFactory
注释方法,其中 returns powermock 的 TestNG 接口实现org.testng.IObjectFactory
即,org.powermock.modules.testng.PowerMockObjectFactory
(或)通过扩展org.powermock.modules.testng.PowerMockTestCase
- 使用@PrepareForTest 准备静态 class 以供 PowerMockit 模拟
我无法在您的代码中使用 PowerMock 的对象工厂接线找到任何对您的引用。你能试试看是否有帮助吗?
请参阅
更新: 为了通过 ClassCastExceptions,您需要将以下注释添加到您的 class.
@org.powermock.core.classloader.annotations.PowerMockIgnore({"javax.ws.*", "org.glassfish.*"})
有关此的更多详细信息,请参阅this Whosebug问题
PS :我假设您正在使用以下注释让 powermock 准备您的测试 class 以进行模拟(您问题中的示例显示了其他内容)
@org.powermock.core.classloader.annotations.PrepareForTest({ResourceController.class})