首页 > 解决方案 > 运行测试用例 ClientHttpResponse 时抛出 401 错误

问题描述

我的单元测试有问题。在我的单元测试中,我得到 401 Unauthorized作为响应状态,我不知道如何解决这个问题。这不是一个 Spring 项目。

我的测试课

@RunWith(MockitoJUnitRunner.class)
public class LTest {

    @Test
    public void test_retrieve() throws Exceptions{
        CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class);
        CloseableHttpResponse mockHttpResponse = mock(CloseableHttpResponse.class);
        HttpEntity mockEntity = mock(HttpEntity.class);
        StatusLine mockStatusLine = mock(StatusLine.class);

        when(mockHttpClient.execute(new HttpGet(new URIBuilder(anyString()).build()))).thenReturn(mockHttpResponse);
        when(mockHttpResponse.getEntity()).thenReturn(mockEntity);
        when(mockHttpResponse.getStatusLine()).thenReturn(mockStatusLine);
        when(mockStatusLine.getStatusCode()).thenReturn(HttpStatus.SC_OK);

        Map<String, Employee> map = sample.retrieve();
        assertNotNull(map);
        assertEquals(1,map.size());
    }

上述测试用例的源代码

CloseableHttpClient httpClient = HttpClientUtils.setupClient(HttpClientBuilder.create()).build();
        String url = "http://someexample.com";
        UriBuilder builder = new URIBuilder(url)
                .setParameter("limit",5)
                .setParameter("centre",centre);

        CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(builder.build()));
        if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
            try{
                String entity = EntityUtils.toString(httpResponse.getEntity());
                ObjectNode node = new ObjectMapper().readValue(entity,ObjectNode.class);
            } catch (IOException e){
                e.printStackTrace();
            }
        }

在运行测试用例时,它显示断言错误,因为它正在通过 catch 块,因为下面的行抛出 401 而不是 200

CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(builder.build()));

谁能帮我解决我遇到的上述错误?

标签: javaunit-testingjunitmockito

解决方案


在测试中,HTTPClient没有被嘲笑,这就是失败的原因。

为了模拟,HTTPClient我们可以遵循以下策略

  1. getHttpClient()在 ClassToBeTested 中提取为
public class HttpClientToBeTested {

    public Map retrieve() throws URISyntaxException, IOException {
        CloseableHttpClient httpClient = getHttpClient();
        String url = "http://someexample.com";

        URIBuilder builder = new URIBuilder(url)
                .setParameter("limit","5")
                .setParameter("centre","centre");

        CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(builder.build()));
        if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
            try{
                String entity = EntityUtils.toString(httpResponse.getEntity());
                //ObjectNode node = new ObjectMapper().readValue(entity,ObjectNode.class);
                Map node = new ObjectMapper().readValue(entity, Map.class); // Assume ObjectNode is a custom class, so for demo using Map.
                return node;
            } catch (IOException e){
                e.printStackTrace();
                throw e;
            }
        }
        return null;
    }

    // New extracted method that will be mocked in the test case
    protected CloseableHttpClient getHttpClient() {
        return HttpClientBuilder.create().build();
    }
}
  1. 接下来在测试类中,我们可以通过在匿名类中继承 ClassToBeTested 来注入模拟,如下所示。
@Test
public void test_retrieve() throws Exception {
    CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class);
    CloseableHttpResponse mockHttpResponse = mock(CloseableHttpResponse.class);
    //HttpEntity mockEntity = mock(HttpEntity.class); Not required since we will pass actual entity
    StatusLine mockStatusLine = mock(StatusLine.class);

    when(mockHttpClient.execute(new HttpGet(new URIBuilder(anyString()).build()))).thenReturn(mockHttpResponse);
    when(mockHttpResponse.getEntity()).thenReturn(new StringEntity("{\"key\":\"value\"}")); // Important: Pass your actual response as string here.
    when(mockHttpResponse.getStatusLine()).thenReturn(mockStatusLine);
    when(mockStatusLine.getStatusCode()).thenReturn(HttpStatus.SC_OK);

    // Code to mock the http client
    HttpClientToBeTested sample = new HttpClientToBeTested() {
        @Override
        protected CloseableHttpClient getHttpClient() {
            return mockHttpClient;
        }
    };

    Map map = sample.retrieve();
    assertNotNull(map);
    assertEquals(1,map.size());
}

更新:模拟 httpClient 后,httpClient.execute()应该返回SC_OK. 但是,发布反序列化响应将失败,因为模拟HttpEntity将返回 null。为了避免它,我们宁愿发送一个StringEntity. 用详细信息更新了实际和测试类。


推荐阅读