Java 如何使用Mockito模拟HttpClient

Java 如何使用Mockito模拟HttpClient,java,junit,mockito,powermockito,pmd,Java,Junit,Mockito,Powermockito,Pmd,这是我正在为之编写junit的实际类。我的HtpClient是私有的和最终的 public class KMSHttpClientImpl implements KMSHttpClient { /** * ObjectMapper Instance. */ private final ObjectMapper objectMapper = new ObjectMapper (); /** * KMS ConnectionManager Instance. */ private fi

这是我正在为之编写junit的实际类。我的HtpClient是私有的和最终的

 public class KMSHttpClientImpl implements KMSHttpClient
 {
/**
 * ObjectMapper Instance.
 */
private final ObjectMapper objectMapper = new ObjectMapper ();

/**
 * KMS ConnectionManager Instance.
 */
private final KMSHttpConnectionManager kmsHttpConnectionManager =
        new KMSHttpConnectionManagerImpl ();

/**
 * HttpClient object.
 */

private final HttpClient httpClient;

/**
 * KMSHttpClient constructor.
 */
public KMSHttpClientImpl ()
{
    // TODO PoolingHttpClientConnectionManager object should be closed after use.
    // TODO This needs to be either singleton or should be kept in static block
    final PoolingHttpClientConnectionManager connectionManager =
            kmsHttpConnectionManager.getConnectionManager();
    httpClient = HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();
}

@Override
public <T> T invokeGETRequest (final String url, final Class<T> clazz)
        throws KMSClientException
{
    final HttpGet httpGet = new HttpGet(url);
    try {
        final HttpResponse response = httpClient.execute(httpGet);
        return objectMapper.readValue(
                response.getEntity().getContent(), clazz);
    } catch (IOException e) {
        throw new KMSClientException("Unable to get the result", e);
    }
}

@Override
public <T> T invokePOSTRequest (final String url, final Object object, final Class<T> clazz)
        throws KMSClientException
{
    final HttpPost httpPost = new HttpPost(url);
    try {
        final HttpResponse response = httpClient.execute(httpPost);
        return objectMapper.readValue(
                response.getEntity().getContent(), clazz);
    } catch (IOException e) {
        throw new KMSClientException("Unable to create the request", e);
    }
}
 }

测试HTTP客户端代码的方法之一是不要模拟HTTPClient对象,而是为HTTP调用创建模拟响应,然后让HPPTClient调用这些URL。 看看Wiremock。 它帮助您创建一个简单的模拟服务器,并且您可以为URL创建存根响应。
然后使用客户端调用URL进行测试。

不能使用普通模拟来模拟最终实例。你需要像这样的东西


有关实现,请参见的答案。

在测试中使用模拟的HttpClient的简单方法是添加第二个构造函数,该构造函数接受HttpClient

公共类KMSHttpClient实现KMSHttpClient
{
私有最终HttpClient HttpClient;
公共KMSHttpClientImpl()
{
最终池客户端连接管理器连接管理器=
kmsHttpConnectionManager.getConnectionManager();
httpClient=HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
}
//此构造函数是包私有的
//是公共的,因此不会被意外使用
//类。如果您的测试
//类不在同一个包中,则
//需要将其设置为公共构造函数。
KMSHTPClientImpl(最终HttpClient HttpClient)
{
this.httpClient=httpClient;
}
}
然后使用此构造函数注入模拟的HttpClient,在测试中既不需要
@InjectMocks
也不需要
@Mock

@测试
public void testPostRequest()引发KMSClientException
{
最终的HttpClient-HttpClient=Mockito.mock(HttpClient.class);
最终HttpResponse响应=准备响应(HttpStatus.SC_OK);
Mockito.when(httpClient.execute(Mockito.any())。然后返回(response);
最终KMSHttpClientImpl KMSHttpClientImpl=新的KMSHttpClientImpl(httpClient);
//运行您的测试。。。
}

我不想使用PowerMock。是否有方法抑制此PMD警告私有字段“httpClient”可能成为最终字段;它只在声明或构造函数中初始化。要抑制PMD警告,请使用注释-请参阅。PowerMock是一种黑客攻击,至少在本例中是这样。测试方法是个问题,
HTTPClient
根本不应该被模仿,需要一种替代方法。我不想使用PowerMock。是否有方法抑制此PMD警告私有字段“httpClient”可能成为最终字段;它只在声明或构造函数中初始化,我建议使用wiremock,它是与powermock不同的库。但我明白你的意思。您想删除final。但是你会被显示为一个问题,因为这是一个问题。我猜您正在使用PMD分析代码。当它做它应该做的事情时,为什么要抱怨呢。!无论如何,如果这是您想要的,您可以为文件添加异常,以不报告源代码分析器中某些文件的问题。这可能会有帮助。我可以通过@SuppressWarnings(“PMD”)这样做,但我要查找与此错误相关的特定代码,而不是PMD。。。。。这个@SuppressWarnings(“PMD”)可以工作,但我需要特定的代码。看起来我们缺少了上下文,不知道您到底在寻找什么。请尝试用更多详细信息更新问题。因此PMD向您发出警告,说明该字段可能是最终字段。在这种情况下,PMD是否正确取决于开发人员。我认为,在这种情况下,PMD是正确的,您真正的问题是您试图模拟不应该模拟的东西(HTTPClient),正如Shubham所说,尝试使用WireMock之类的东西,这是测试在网络上进行调用的类的更好方法,这意味着您将拥有更好的结构化代码,PMD警告将消失,因为该字段是最终字段。一切都解决了。
public class KMSHttpClientImplTest
{

/**
 * Injecting mocks KMSHttpClientImpl.
 */
@InjectMocks
private KMSHttpClientImpl kmsHttpClientImpl;

/**
 * Mock HttpClient.
 */
@Mock
private HttpClient httpClient;


/**
 * Initial SetUp Method.
 */
@Before
public void setUp ()
{
    initMocks(this);
}

/**
 * Method to test postRequest Method.
 * @throws KMSClientException
 */
@Test
public void testPostRequest () throws KMSClientException
{
    final OrganizationRequest request = getOrganizationRequest();
    final HttpResponse response = prepareResponse(HttpStatus.SC_OK);
    try {
        Mockito.when(httpClient.execute(Mockito.any())).thenReturn(response);
        final OrganizationResponse organizationResponse = kmsHttpClientImpl.invokePOSTRequest(
                ORG_TEST_URL, request, OrganizationResponse.class);
        assertEquals("Id should match", ORG_ID, organizationResponse.getId());
    } catch (IOException e) {
        throw new KMSClientException("Unable to create the request", e);
    }
      }

/**
 * Method to test getRequest Method.
 * @throws KMSClientException
 */
@Test
public void testGetRequest () throws KMSClientException
{
    try {
        final HttpResponse response = prepareResponse(HttpStatus.SC_OK);
        Mockito.when(httpClient.execute(Mockito.any())).thenReturn(response);
        final OrganizationResponse organizationResponse = kmsHttpClientImpl.invokeGETRequest
                (ORG_TEST_URL, OrganizationResponse.class);
        assertEquals("Id should match", ORG_ID, organizationResponse.getId());
    }  catch (IOException e) {
        throw new KMSClientException("Unable to create the request", e);
    }
}

/**
 * Method to organizationRequest Object.
 * @return OrganizationRequest object
 */
public OrganizationRequest getOrganizationRequest ()
{
    return OrganizationRequest.builder().id("test").build();
}

/**
 * Method to getOrganizationResponse String.
 * @return String Object
 */
public String getOrganizationResponse ()
{
    final Map obj=new HashMap();
    obj.put("id", ORG_ID);
    obj.put("uuid", ORG_UUID);
    obj.put("orgKeyId", ORG_KEYID);
    return JSONValue.toJSONString(obj);
}

/**
 * Method to prepare Response.
 * @param expectedResponseStatus
 * @return HttpResponse
 */
private HttpResponse prepareResponse (final int expectedResponseStatus)
{
    final HttpResponse response = new BasicHttpResponse(new BasicStatusLine(
            new ProtocolVersion("HTTP", 1, 1),
            expectedResponseStatus, ""));
    response.setStatusCode(expectedResponseStatus);
    final HttpEntity httpEntity = new StringEntity(getOrganizationResponse(),
            ContentType.APPLICATION_JSON);
    response.setEntity(httpEntity);
    return response;
     }
    }