【问题标题】:Why isnt mockito injecting the right response?为什么 mockito 没有注入正确的响应?
【发布时间】:2015-08-13 00:40:30
【问题描述】:

我正在尝试以下列方式使用 mockito。

这是主类IClient的一部分。

public LoginResponse doLogin() {

        WebTarget target = buildTarget();

        MultivaluedMap<String, Object> authHeaders = prepareHeaders();
        Builder buildRequest = buildRequest(authHeaders,target); 
        Response loginRsp = buildRequest
                .post(Entity.entity(" Valid JSON string",
                        MediaType.APPLICATION_JSON_TYPE));
        if(loginRsp == null)
            LOGGER.error("Response was null");// Response is always returned as null.

这是我的测试代码

@Test
public void testdoLoginPass(){
        Response response = Response.ok().build();
        WebTarget webTarget = inner.buildTarget();
        Builder buildRequest = inner.buildRequest( getMockHeaders(),webTarget);

        when(buildRequest.post(Entity.entity(anyString(),
                MediaType.APPLICATION_JSON_TYPE))).thenReturn(response);
      Assert.assertNotNull(inner.doLogin());

}

我似乎无法弄清楚为什么响应总是为空。任何想法将不胜感激。

inner 是匿名的内部类对象,为buildTarget()buildRequest() 提供相应的模拟值。我能够看到正确的模拟值是通过调试生成的。 这是匿名内部类

inner= new IClient(client, propConfig){
            WebTarget buildTarget(){
                WebTarget target= mock(WebTarget.class);
                LOGGER.error("Returning mock");
                return target;

            }
          Builder buildRequest(final MultivaluedMap<String, Object>  Headers,WebTarget target){
              Builder builder = mock(Builder.class);
              LOGGER.error("Returning mock");
              return builder;
          }
        };

编辑--基于使用相同实例的建议。

这是折射版。

@Test 
    public void testdoIusLoginPass(){


    inner= new IClient(client, propConfig){
        WebTarget buildIUSTarget(){
            WebTarget target= mock(WebTarget.class);
            LOGGER.error("Returning mock");
            return target;

        }
      Builder buildRequest(final MultivaluedMap<String, Object> authHeaders,WebTarget target){
          builder = mock(Builder.class);
          LOGGER.error("HashCode for Builder from inner Relevant method "+ builder.hashCode());
          LOGGER.error("Returning mock");
          return builder;
      }
    };
    Response response = Response.ok().build();
    WebTarget target = innerIUS.buildIUSTarget();
    builder = innerIUS.buildRequest( getMockHeaders(),target);

    when(builder.post(Entity.entity(any(String.class),
           MediaType.APPLICATION_JSON))).thenReturn(response)
    Assert.assertNotNull(inner.doLogin());
}

实际方法内

 public LoginResponse doIusLogin() {
    WebTarget target = buildIUSTarget();

    MultivaluedMap<String, Object> authHeaders = prepareIUSHeaders();
     builder = buildRequest(authHeaders,target); 
     LOGGER.error("HashCode for Builder from doLogin "+ builder.hashCode());//identical hash codes
    Response loginRsp = builder
            .post(Entity.entity("Valid JSON String",
                    MediaType.APPLICATION_JSON_TYPE));
    if(loginRsp == null)
        LOGGER.error("Response was null");// Still null. 

响应仍然为空。想法?

【问题讨论】:

  • 感谢您的跟进。你能详细说明注射的意思吗?匿名内部类不是已经这样做了吗?

标签: java unit-testing mocking testng mockito


【解决方案1】:

您必须将存根与模拟对象保持在一起。例如

final Response response = Response.ok().build();

IClient inner = new IClient(client, propConfig){
  Builder buildRequest(MultivaluedMap<String, Object> Headers, WebTarget target){
    Builder builder = mock(Builder.class);
    when(builder.post(any(Entity.class)).thenReturn(response)
    return builder;
  }
};

assertNotNull(inner.doLogin());

还有一个小问题——这个测试几乎没有测试任何东西。

【讨论】:

  • 另外补充一下,你是对的。测试在这一点上什么也没做,我正在通过它并注意到这个奇怪的地方。没有修复就无法继续。
【解决方案2】:

您的when 匹配器从未使用过,这就是为什么它是null

Mockito 不做深度参数比较,所以它比较

Entity.entity(anyString(), MediaType.APPLICATION_JSON_TYPE)

Entity.entity(" Valid JSON string", MediaType.APPLICATION_JSON_TYPE)

使用Entity.equals,但它们不匹配。您应该编写自定义匹配器或将之前的表达式替换为 any(Entity.class)

编辑:此外,您在测试代码和测试类中使用了 Builder 的不同实例。您应该参考同一个实例。将其注入到被测试的类中。

编辑#2:每次调用inner.buildRequest 时,您都在重新创建Builder。在你的测试代码和你测试的类代码中写上System.out.println(buildRequest.hashCode());,你会看到它们是两个不同的实例。

抱歉,我无法为您提供解决问题所需的代码 - 至少我没有看到太多的测试基础架构能够做到这一点。

但是我应该说没有DI 的测试非常复杂。我建议您集成一些框架(Guice 或 Spring)并开始使用它,否则您的测试过程可能很快就会成为一场噩梦。

【讨论】:

  • 所以基本上你的意思是对的? when(buildRequest.post(Entity.entity(any(Entity.class), MediaType.APPLICATION_JSON_TYPE))).thenReturn(response); 。但是响应仍然为空。
  • 我的意思是:when(buildRequest.post(any(Entity.class))).thenReturn(response);
  • 我更正了您的建议(包括右括号)when(buildRequest.post(any(Entity.class))).thenReturn(response)。响应仍然为空:(
  • Entity.entity 方法是否返回 Entity.class 的实例?
  • 我认为是 String 。这是 eclipse 告诉我的&lt;String&gt; Entity&lt;String&gt; javax.ws.rs.client.Entity.entity(String entity, String mediaType
【解决方案3】:

您应该定义被模拟对象的行为。 例如:

when(mockedList.get(anyInt())).thenReturn("element");

http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html

【讨论】:

  • 这与问题几乎没有关系。模拟行为在内部匿名类中定义。
猜你喜欢
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多