问题
A rest service using Jersey developed. Now I want to write some integration tests for this web service but since not every class being used from the web service is already implemented I need to mock some of them. For example I have the following 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();
}}
Then i want to test do integration test with Jersey test framework and TestNg + Powermock (mock new object with constructor).
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");
}
}
My pom dependecy:
<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>
But in runtime, the instance ServiceA in getIt() method is still initalized as new ServiceA object not the mockA object.
Any idea about it? Thanks,
if add PowerMockIgnore({"javax.ws.", "org.glassfish."}), then see below exception:
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
回答1:
I believe the mock is perhaps not happening because you dont have the PowerMock's objectfactory implementation wired into TestNG.
In order to get powermockito and TestNG to work with each other you have to do the following :
- Configure TestNG to use the PowerMock object factory : You can do this either via the attribute
object-factory
in your<suite>
tag of your suite xml or via an@org.testng.annotations.ObjectFactory
annotated method which returns the powermock's implementation of TestNG interfaceorg.testng.IObjectFactory
viz.,org.powermock.modules.testng.PowerMockObjectFactory
(or) by extendingorg.powermock.modules.testng.PowerMockTestCase
- Use @PrepareForTest to prepare your static class for being mocked by PowerMockit
I couldnt find any reference to you using the PowerMock's Object factory wiring in, in your code. Can you please try doing that and see if that helps ?
Please see here for full details.
Update: In order to get past the ClassCastExceptions you would need to add the below annotation to your class.
@org.powermock.core.classloader.annotations.PowerMockIgnore({"javax.ws.*", "org.glassfish.*"})
For more details around this, please refer to this stackoverflow question
PS : I am assuming that you are using the following annotation to have powermock prepare your test class for mocking (Your sample in your question is showing something else)
@org.powermock.core.classloader.annotations.PrepareForTest({ResourceController.class})
来源:https://stackoverflow.com/questions/45528317/issue-when-test-a-jersey-rest-service-using-powermock-with-jersey-test-testng