2013-10-24 87 views
7

我在创建模拟响应对象以与我的单元测试一起使用时遇到问题。我正在使用org.glassfish.jersey.core.jersey-client版本2.3.1来实现我的RESTful客户端和mockito版本1.9.5以帮助我处理模拟对象。这是我的测试代码:无法模拟Glassfish Jersey客户端响应对象

@Test 
public void testGetAll() throws IOException { 
    // Given 
    String expectedResource = "expectedResource" 

    final Response expectedRes = Response.ok(expectedResource, MediaType.APPLICATION_JSON).build(); 
    String receivedResource; 

    BDDMockito.given(this.client.getSimpleClient().getAllWithResponse()).willReturn(expectedRes); 

    // When 
    receivedResource = this.client.getAll(); 

    // Then 
    Assert.assertNotNull("Request constructed correctly and response received.", receivedResource); 
    Assert.assertEquals("Resource is equal to expected.", expectedResource, receivedResource); 
} 

执行this.client.getAll();时会出现此问题。下面是该方法的代码:

public String getAll() throws GenericAragornException, ProcessingException{ 
    Response response = this.simpleClient.getAllWithResponse(); 

    if (response.getStatus() != 200) { 
     processErrorResponse(response); 
    } 

    String entity = response.readEntity(String.class); 

    // No errors so return entity converted to resourceType. 
    return entity; 
} 

注意,我用嘲笑的手动创建响应this.simpleClient.getAllWithResponse()方法。当它到达response.readEntity(resourceListType);指令时,Jersey会抛出以下异常:java.lang.IllegalStateException - Method not supported on an outbound message.。经过大量研究和调试后,出于某种原因,当我使用响应构建器(如Response.ok(expectedResource, MediaType.APPLICATION_JSON).build();)创建响应时,它会将其创建为OutboundResponse,而不是将其创建为InboundResponse。后者是唯一允许使用Response.readEntity()方法的人。如果它是OutboundResponse,则引发异常。

但是,我找不到任何方法将手动创建的响应转换为InboundResponse。所以我的测试是注定的:(你们/ gals对我在这里可以做什么有所了解吗?我不想用Mockito来模拟Response对象,因为我认为它可能是代码异味,因为它违反了得墨忒耳,真诚的,我的想法在这里。像这样的事情应该是简单明了。

回答

5

,因为当你使用ResponseBuilder,它返回一个OutboundJaxrsResponse消息不能readEntity()处理我有这个错误。

我注意到只有当我直接调用Jax-RS组件时才有这个错误,例如,如果我有DefaultController注释了@Path("/default"),并且如果我试图直接调用它的方法,我就不能使用readEntity()和你有同样的错误。

defaultController.get(); 

现在,当我用的是grizzly2测试提供商和使用客户端定位的REST URL(在之前的情况下,它是/default),我在响应接收到的消息是一个ScopedJaxrsResponse。然后我可以使用readEntity()方法。

target("/default").request.get(); 

在你的情况,你才能与ResponseBuilder内置的响应不是由球衣处理回复嘲笑SimpleClient的。这可以直接调用我的DefaultController方法。

如果不嘲笑readEntity()方法,我建议您找到一种方法让您的回复由Jersey处理并转换为ScopedJaxrsResponse

希望有所帮助。

+0

托马斯,感谢您的输入!只有一个问题......如果是你......你会嘲笑readEntity()方法吗? –

+0

这取决于你想测试什么? – Thomas

+0

getAll方法执行它应该执行的操作,并根据它接收的内容返回它应该返回的内容。 –

2

而不是使用readEntity(OutputClass.class)你可以这样做:

OutputClass entity = (OutputClass)outboundJaxrsResponse.entity 
+0

不理想不得不改变源代码,但这个伎俩。谢谢。 –

0

我解决了嘲讽的回应:

@Spy Response response; 

... 

// for assignments in code under testing: 
doReturn(response).when(dwConnector).getResource(anyString()); 

// for entity and response status reading: 
doReturn("{a:1}".getBytes()).when(response).readEntity(byte[].class); 
doReturn(200).when(response).getStatus(); 

这些可以帮助,如果您的转向是手动创建一个ScopedJaxrsResponse代替:

1

您还可以使用模拟的Mockito响应:

final Response response = Mockito.mock(Response.class); 
Mockito.when(response.getStatus()).thenReturn(responseStatus); 
Mockito.when(response.readEntity(Mockito.any(Class.class))).thenReturn(responseEntity); 
Mockito.when(response.readEntity(Mockito.any(GenericType.class))).thenReturn(responseEntity); 

responseStatus是与响应关联状态代码和responseEnitty是要返回过程中的实体。您可以使用该模拟作为Mockito中的返回语句(例如... thenReturn(response))。

在我的项目中,我为不同类型的mock(在这种情况下为Response)创建了构建器,因此我可以轻松地按需构建所需的mock,例如,状态码200和附加的一些自定义实体的响应。

2

对我来说,这些答案都不起作用,因为我试图编写一个服务器端单元测试,测试生成的Response实例本身的主体。我通过调用String entity = readEntity(String.class)这样的一行来得到这个例外。我不想嘲笑Response的对象,我想测试它。

对我来说,修复是上述问题的行替换到一个像:

String entity = (String) outboundJaxrsResponse.getEntity(); 
+0

或者'''LinkedHashMap结果=(LinkedHashMap)successResponse.getEntity();'''.. –

+0

谢谢,这比接受的响应更有帮助! –

相关问题