我在创建模拟Response对象以用于单元测试时遇到问题。我正在使用org.glassfish.jersey.core.jersey-client版本2.3.1来实现我的RESTful客户端,并使用mockito版本1.9.5来帮助我处理模拟对象。这是我的测试代码:

@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;
}

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

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

最佳答案

我遇到此错误是因为当您使用ResponseBuilder时,它返回了OutboundJaxrsResponse无法处理的readEntity()消息。

我注意到只有在直接调用Jax-RS组件时才出现此错误。例如,如果我用DefaultController注释了@Path("/default"),并且如果我尝试直接调用其方法,则无法使用readEntity()并遇到与您相同的错误。

defaultController.get();

现在,当我使用grizzly2测试提供程序并使用客户端将Rest Url作为目标(在以前的示例中,它是/default)时,我收到的响应消息是ScopedJaxrsResponse。然后,我可以使用readEntity()方法。
target("/default").request.get();

在您的情况下,您 mock 了simpleClient,以便使用未经jersey处理的ResponseBuilder构建的响应进行回复。这相当于直接调用我的DefaultController方法。

在不 mock readEntity()方法的情况下,建议您找到一种方法来使Jersey处理您的响应并将其转换为ScopedJaxrsResponse

希望能有所帮助。

09-10 10:12