当前位置: 首页 > 知识库问答 >
问题:

无法模拟玻璃鱼泽西岛客户端响应对象

戚兴邦
2023-03-14

我在创建用于单元测试的模拟响应对象时遇到了问题。我使用< code > org . glassfish . jersey . core . jersey-client 版本2.3.1来实现我的RESTful客户端,使用< code>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;
}

请注意,我在嘲笑this.simpleClient。getAllWithResponse()方法和手动创建的响应。当它到达<code>响应时。readEntity(resourceListType) 指令中,Jersey抛出以下异常:<code>java.lang.IllegalStateException-出站消息不支持此方法。。经过大量的研究和调试,由于某些原因,当我使用响应生成器(如<code>Response)创建响应时,结果证明了这一点。ok(expectedResource,MediaType.APPLICATION_JSON)。build()它将其创建为OutboundResponse,而不是InboundRespose。只有后者才允许使用<code>响应。readEntity()方法。如果是OutboundResponse,则抛出异常。

但是,我找不到任何方法将手动创建的响应转换为InboundResponse。所以我的测试注定要失败。你们知道我在这里能做什么吗?我不想用Mockito来嘲笑响应对象,因为我认为这可能是一种代码味道,因为它违反了Demeter法则。说真的,我已经没有主意了。像这样的事情应该简单明了。

共有3个答案

秦才
2023-03-14

我自己也遇到了这个问题,试图通过使用<code>Response.ok(实体)将客户端模拟为远程服务。build()然后允许我的客户机代码对来自伪造服务器的响应执行response.readEntity(…)

我在中讨论这个问题https://codingcraftsman.wordpress.com/2018/11/26/testing-and-mocking-jersey-responses/

问题是< code>Response.build()方法旨在生成出站响应,该响应在被真实客户端接收和反序列化之前应该被序列化。< code>readEntity方法应在反序列化时调用。

正如其他发帖人所观察到的那样,在出站响应阅读实体将为您提供您放入的确切实体对象。您甚至可以将其投射到所需的任何类型。当然,这不适用于真正的入站响应,因为入站响应仅具有来自服务器的入站流的文本/二进制文件。

我编写了以下代码,以允许我使用 mockito 强制出站响应假装为入站响应

  /**
   * Turn a locally made {@link Response} into one which can be used as though inbound.
   * This enables readEntity to be used on what should be an outbound response
   * outbound responses don't support readEntity, but we can fudge it using
   * mockito.
   * @param asOutbound response built as though being sent to the received
   * @return a spy on the response which adds reading as though inbound
   */
  public static Response simulateInbound(Response asOutbound) {

    Response toReturn = spy(asOutbound);
    doAnswer(answer((Class<?> type) -> readEntity(toReturn, type)))
        .when(toReturn)
        .readEntity(ArgumentMatchers.<Class<?>>any());
    return toReturn;
  }

  // use the getEntity from the real object as
  // the readEntity of the mock
  @SuppressWarnings("unchecked")
  private static <T> T readEntity(Response realResponse, Class<T> t) {
    return (T)realResponse.getEntity();
  }
常乐
2023-03-14

我有这个错误,因为当您使用响应生成器时,它会返回一个无法使用readEntity()处理的Out边界JaxrsACK消息。

我注意到只有在直接调用Jax-RS组件时才出现这个错误。例如,如果我用@Path(“/default”)注释了DefaultController,并且如果我试图直接调用它的方法,我就不能使用readEntity(),并且出现了与您相同的错误。

defaultController.get();

现在,当我使用 grizzly2 测试提供程序并使用客户端来定位 Rest Url(在前面的案例中,它是 /default)时,我在响应中收到的消息是 ScopedJaxrsResponse。然后我可以使用readEntity()方法。

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

在您的案例中,您嘲笑了simpleClient,以便使用使用响应生成器构建的响应进行回复,该响应不是由jersey处理的。这与直接调用我的DefaultController方法相当。

在不嘲笑readEntity()方法的情况下,我建议您找到一种方法,让您的响应由泽西处理并变成ScopedJaxrsACK

希望有所帮助。

孔棋
2023-03-14

您还可以使用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);

响应状态是与响应相关联的状态代码,响应Enitty当然是您要返回的实体。您可以使用该模拟作为Mockito中的返回状态(例如... then返回(响应))。

在我的项目中,我为不同类型的模拟(在这种情况下是响应)创建生成器,所以我可以很容易地按需构建所需的模拟,例如,状态代码为200的响应和一些附加的自定义实体。

 类似资料:
  • 我已经完成了在glassfish v4中添加SSL证书的步骤。我已经通过浏览器和java swing客户端验证了它的有效性(我在客户端使用apache的http客户端库) 什么不工作是管理控制台!由于成功导入SSL,我不能再连接到管理控制台,http://www.myhost.com:4848,我仍然得到登录屏幕,总是工作的管理员用户名/密码组合已停止工作。我也注意到当尝试部署一个网络应用程序从n

  • 问题内容: 我正在尝试使用Jersey客户端模拟对我的Web服务的HTTP请求。我尝试实现文档中的简单示例。这是我的短代码: 我什至没有实现整个示例,因为当前我在最后一行收到一个异常: 我只将此依赖项添加到我的: 我试图用谷歌搜索问题,以及调试应用程序,但我真的看不出问题出在哪里。 编辑 所有Maven依赖项: 问题答案: 这看起来像与JAX-RS API版本(包含MultiValuedMap)有

  • 我想返回一个临时重定向,使用AsyncACK。 下面的“工作”(因为没有错误),但似乎不是异步的(它一次处理一个请求)。 这应该工作吗?如果我明确需要像https://jersey.github.io/documentation/latest/async.html#d0e9895一样启动一个新线程,返回响应是什么样子的?

  • 问题内容: 我正在下载Java EE,似乎有许多不同的下载选项。我不确定应该选择哪一个。Java EE似乎与GlassFish打包在一起。谁能告诉我这是什么,它对我有什么好处? 其次,如果我只是想玩转并了解Java EE,那么对我来说下载的是什么?列出选项的链接在下面… Java EE下载选项 问题答案: 首先,将近五年前它被称为Java EE。首字母缩略词J2EE仍指5.0之前的旧Java EE

  • 我将mysql驱动程序放入glassfish/admin1/lib,我在尝试与GlassFish 3.1.2建立连接时收到此错误 为SimpleCRUD_ConnectionPool Ping连接池失败。类名错误或未为:com设置类路径。mysql。jdbc。jdbc2。可选择的MysqlDataSource请检查服务器。记录更多细节。 野兔配置: 池名称:SimpleCRUD_Connectio

  • 不确定发生了什么,但我不知道我的反应在哪里被劫持了。