【问题标题】:Mock request/post with mockito使用 mockito 模拟请求/发布
【发布时间】:2017-08-30 19:07:15
【问题描述】:

我在使用测试 (JUnit/Mockito) 覆盖以下函数“postJson”时遇到问题,并且找不到模拟行 response = getTarget(path).request().post(entity, Map.class);

//Constructor
public HttpService() {
    this.client = ClientBuilder.newClient();
}

Client client;

public Map<String, ?> postJson(String path, Map<String, ?> data){
    Map<String, ?> response = null;

    try {
        Entity<Map<String, ?>> entity = Entity.entity(data, MediaType.APPLICATION_JSON);
        response = getTarget(path).request().post(entity, Map.class);   
    } catch (Exception e) {
        LOG.error(e.toString());
    }

    return response;
}

public WebTarget getTarget(String path){
    return client.target(BASE_URI + path);
}

我目前的测试

@Test
public void postJsonTest(){
    assertEquals(null,new HttpService().postJson("", new HashMap<String,Integer>()));

    //Verifica se a função de comunicação com servidor é chamda
    Map<String,String> resposta = new HashMap<String,String>();
    HttpService mock = spy(HttpService.class);  

    assertEquals(mock.postJson("",resposta),null);

    Mockito.verify(mock,Mockito.atLeast(1)).postJson("", resposta);
    Mockito.verify(mock,Mockito.atLeast(1)).getTarget(Mockito.anyString());
}

在“request()”之后,我找不到制作测试代码的方法。任何人都可以给我一个例子/解释我如何用 mockito 覆盖这个功能?

【问题讨论】:

  • 帖子中添加,client是类中的一个属性
  • 客户端已经在类的构造函数中实例化了
  • 你的问题是构造函数中的静态方法调用。您可能想要第二个不调用它的构造函数。然后您可以在该构造函数中传递一个模拟,其中 target 方法被模拟。您需要模拟 WebTarget,还需要模拟 request 返回的任何内容。
  • 如果以后有时间我会写一个完整的答案,如果没有其他人这样做。
  • 我编辑了这个问题,我只是不知道如何在该行的请求之后覆盖任何内容。

标签: java unit-testing testing mockito junit4


【解决方案1】:

鉴于HttpService 上的这个额外构造函数:

public HttpService(Client client) {
    this.client = client;
}

以下测试将通过:

@RunWith(MockitoJUnitRunner.class)
public class HttpServiceTest {

    @Mock
    private Client client;
    @Mock
    private WebTarget webTarget;
    @Mock
    private RequestEntity requestEntity;

    private HttpService httpService;

    @Before
    public void setUp() {
        this.httpService = new HttpService(client);
    }

    @Test
    public void postJsonTest() {
        String path = "/a/path";
        Map<String, ?> data = new HashMap<>();

        // the postJson method features this chained call: getTarget(path).request().post(entity, Map.class)
        // so we have to mock each object created in that chain

        // covers getTarget(path)
        Mockito.when(client.target(Mockito.anyString())).thenReturn(webTarget);

        // covers request()
        Mockito.when(webTarget.request()).thenReturn(requestEntity);

        // covers post()
        Map<String, Object> expected = new HashMap<>();

        Mockito.when(requestEntity.post(Mockito.any(Entity.class), Mockito.eq(Map.class))).thenReturn(expected);
        Map<String, ?> actual = httpService.postJson(path, data);
        Assert.assertSame(expected, actual);
    }
}

注意事项:

  • 这依赖于提供一个新的 HttpService 构造函数,该构造函数接受 Client 实例。
  • 通过HttpService 的无参数构造函数内部的静态方法调用来实例化Client 的现有方法需要使用PowerMockito。一种对测试更友好的方法是提供一个接受 ClientClientFactory 的构造函数,ClientFactory 的默认实现是 ClientBuilder.newClient()
  • postJson() 方法具有链式调用 (getTarget(path).request().post(entity, Map.class)) 的特点,它要求我们模拟该链中返回的每个对象,即 ClientWebTargetRequestEntity
  • 我的示例涉及到一些细节,例如RequestEntity 的泛型类型以及精确参数匹配器与一般参数匹配器的选择。您将能够在那里做出正确的选择,因为您最了解 (a) 实现的细节和 (b) 测试的意图,但上述测试至少向您展示了模拟调用链需要每个对象在那个链中被嘲笑。

【讨论】:

  • 是的,这或多或少是我对我的 cmets 的想法。谢谢你省去了我自己写这篇文章的麻烦。赞成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
  • 2012-11-01
  • 2022-12-11
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多