我确实在使用TestNG和RESTeasy时遇到了一个非常烦人的问题。
我有一个类,它针对一个使用RESTeasy框架公开自身的API类运行多个测试。
但是,如果我让测试运行maven(mvn test),那么我会得到以下异常:
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)
测试只是调用API obejct的方法,该方法返回一个Response对象(来自RESTeasy)。作为测试框架,我使用TestNG。
测试方法
@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"));
}
问题说明
看起来RESTeasy框架在不同的类加载器中加载RuntimeDelegate。如果我看一下源代码,那么在RuntimeDelegate上有以下方法(涵盖第126行):RuntimeDelegate.java。
因此,与错误相关的主要语句是instanceof check:
if (!(delegate instanceof RuntimeDelegate))
如果我检查委托实例的类加载器与RuntimeDelegate的类加载器,那么我得到以下输出:
delegate.getClass().getClassLoader() -> org.powermock.core.classloader.MockClassLoader@31e46a68
RuntimeDelegate.class.getClassLoader() -> sun.misc.Launcher$AppClassLoader@3c0fabe9
我知道这当然不起作用,但我想知道为什么RESTeasy的东西被加载到MockClassLoader而不是另一个。特别是因为我没有模拟被测试的TokenAPI。
奇怪的事实
奇怪的是,当我从IntelliJ运行测试时(我选择只运行包含产生错误的方法的给定类的所有测试),然后它就会运行。看起来它与mvn测试运行maven项目中的所有测试(或者至少就是我的猜测)有关。
答案 0 :(得分:7)
不幸的是我无法告诉你为什么会这样,但我可以告诉你如何解决这个问题。
问题是,PowerMockito扫描了类路径并添加了RESTeasy类(位于包'javax.ws。*'中。因此,上面提到的RuntimeDelegate是由PowerMockito类加载器加载的,后来引发了问题,将该类与不同类加载器中的类进行比较。
要解决此问题,请告诉PowerMockito在扫描类时忽略javax.ws包:
@PowerMockIgnore({"javax.ws.*"})
答案 1 :(得分:1)
在将我的应用程序部署到JBoss v6.1时,我遇到了同样的问题 - 不知怎么理解问题是由于jesrey-core和jboss'jaxrs-api jar中存在的RuntimeDelegate.class的相同包结构
下面是我的pom.xml
<!-- For Restful Client -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.8</version>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>resteasy-jaxrs</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- For Jackson (JSON Utility) -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.9</version>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
</exclusion>
</exclusions>
</dependency>
我的战争部署到JBoss后,刚从jboss'server \ default \ deployers文件夹中删除了resteasy.deployer文件夹。在我的应用程序中运行它。
如果有人解释为什么这个错误以这种方式得到解决,我会很高兴吗? (我认为当开发人员可以在他们的应用程序中自己包含jar时,JBoss'已经不必要地附带了resteasy.deployers jar) - 不要隐瞒我尝试在Tomcat上部署我的战争并且它运行顺利。
答案 2 :(得分:0)
我通过更改@view_config(route_name='image', renderer='../templates/image.pt')
def image(request):
import os
filename = request.matchdict.get('filename')
filepath = os.path.join(request.registry.settings['image_dir'], filename)
return {'name': 'Hello View', 'filepath': filepath}
中的org.glassfish.jersey
版本来解决了这个问题
下面是我的pom.xml
pom.xml