Java 如何使用Mockito模拟HttpClient
这是我正在为之编写junit的实际类。我的HtpClient是私有的和最终的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
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;
}
}