I do experience a really annoying problem with TestNG and RESTeasy.
I do have a class that runs several tests against an API class which uses the RESTeasy framework to expose itself.
However if I let the test run with maven (mvn test), then I get the following exception:
java.lang.LinkageError: ClassCastException: attempting to castjar:file:/C:/Users/rit/.m2/repository/org/jboss/resteasy/jaxrs-api/2.3.0.GA/jaxrs-api-2.3.0.GA.jar!/javax/ws/rs/ext/RuntimeDelegate.classtojar:file:/C:/Users/rit/.m2/repository/org/jboss/resteasy/jaxrs-api/2.3.0.GA/jaxrs-api-2.3.0.GA.jar!/javax/ws/rs/ext/RuntimeDelegate.class
at javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:126)
at javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:96)
at javax.ws.rs.core.Response$ResponseBuilder.newInstance(Response.java:394)
at javax.ws.rs.core.Response.status(Response.java:116)
at javax.ws.rs.core.Response.status(Response.java:130)
at com.pd.api.TokenAPI_V1.validateAccessToken(TokenAPI_V1.java:141)
at com.test.pd.api.TokenAPI_V1Test.testIfValidAccessTokenReturnsCorrectHTTPHeadersWhenTokenIsNotFound(TokenAPI_V1Test.java:359)
The test does nothing more than calling a method of the API obejct which returns a Response object (from RESTeasy). As testing framework I do use TestNG.
Test Method
@Test
public void testIfValidAccessTokenReturnsCorrectHTTPHeadersWhenTokenIsNotFound() throws InvalidAccessTokenException {
Mockito.when(tokenService.validateAccessToken(TestConstants.ACCESS_TOKEN)).thenThrow(new InvalidAccessTokenException());
Response response = tokenAPI_v1.validateAccessToken(TestConstants.ACCESS_TOKEN, TestConstants.USER_AGENT);
assert "no-store".equals(response.getMetadata().getFirst("Cache-Control"));
assert "no-cache".equals(response.getMetadata().getFirst("Pragma"));
}
Issue Description
It looks like the RESTeasy framework loads the RuntimeDelegate in a different class loader. If I take a look at the source code, then there is the following method at the RuntimeDelegate (which covers line 126): RuntimeDelegate.java.
So the main statement that is related to the error is the instanceof check:
if (!(delegate instanceof RuntimeDelegate))
If I check the classloader of the delegate instance vs the classloader of the RuntimeDelegate, then I get the following output:
delegate.getClass().getClassLoader() -> org.powermock.core.classloader.MockClassLoader@31e46a68
RuntimeDelegate.class.getClassLoader() -> sun.misc.Launcher$AppClassLoader@3c0fabe9
I am aware of that this of course doesn't work but I wonder why the RESTeasy stuff is loaded in the MockClassLoader and not in the other one. Especially as I don't mock the TokenAPI which gets tested.
Strange Facts
The strange thing is, that when I run the tests out of IntelliJ (I choose only to run all tests from the given class which contains the method that produces the error), then it runs through. It looks like it is somehow related to the fact that mvn test runs all tests from the maven project (or at least that's what I guess).
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…