応答でスタブ化されたJSONオブジェクトを返すために、下記のメソッドの1つをモックするために、Apache HttpClientインターフェイスをモックしようとしています。
HttpResponse response = defaultHttpClient.execute(postRequest);
誰かがいくつかのサンプルコードでこれを達成する方法を提案できますか?あなたの助けは大歓迎です。
ありがとう
以下は、MockitoとApache HttpBuilderを使用してコードをテストするために行ったことです。
テスト対象のクラス:
import Java.io.BufferedReader;
import Java.io.IOException;
import javax.ws.rs.core.Response.Status;
import org.Apache.http.HttpResponse;
import org.Apache.http.client.HttpClient;
import org.Apache.http.client.methods.HttpGet;
import org.Apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StatusApiClient {
private static final Logger LOG = LoggerFactory.getLogger(StatusApiClient.class);
private String targetUrl = "";
private HttpClient client = null;
HttpGet httpGet = null;
public StatusApiClient(HttpClient client, HttpGet httpGet) {
this.client = client;
this.httpGet = httpGet;
}
public StatusApiClient(String targetUrl) {
this.targetUrl = targetUrl;
this.client = HttpClientBuilder.create().build();
this.httpGet = new HttpGet(targetUrl);
}
public boolean getStatus() {
BufferedReader rd = null;
boolean status = false;
try{
LOG.debug("Requesting status: " + targetUrl);
HttpResponse response = client.execute(httpGet);
if(response.getStatusLine().getStatusCode() == Status.OK.getStatusCode()) {
LOG.debug("Is online.");
status = true;
}
} catch(Exception e) {
LOG.error("Error getting the status", e);
} finally {
if (rd != null) {
try{
rd.close();
} catch (IOException ioe) {
LOG.error("Error while closing the Buffered Reader used for reading the status", ioe);
}
}
}
return status;
}
}
テスト:
import Java.io.IOException;
import org.Apache.http.HttpResponse;
import org.Apache.http.StatusLine;
import org.Apache.http.client.ClientProtocolException;
import org.Apache.http.client.HttpClient;
import org.Apache.http.client.methods.HttpGet;
import org.Apache.http.conn.HttpHostConnectException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
public class StatusApiClientTest extends Mockito {
@Test
public void should_return_true_if_the_status_api_works_properly() throws ClientProtocolException, IOException {
//given:
HttpClient httpClient = mock(HttpClient.class);
HttpGet httpGet = mock(HttpGet.class);
HttpResponse httpResponse = mock(HttpResponse.class);
StatusLine statusLine = mock(StatusLine.class);
//and:
when(statusLine.getStatusCode()).thenReturn(200);
when(httpResponse.getStatusLine()).thenReturn(statusLine);
when(httpClient.execute(httpGet)).thenReturn(httpResponse);
//and:
StatusApiClient client = new StatusApiClient(httpClient, httpGet);
//when:
boolean status = client.getStatus();
//then:
Assert.assertTrue(status);
}
@Test
public void should_return_false_if_status_api_do_not_respond() throws ClientProtocolException, IOException {
//given:
HttpClient httpClient = mock(HttpClient.class);
HttpGet httpGet = mock(HttpGet.class);
HttpResponse httpResponse = mock(HttpResponse.class);
StatusLine statusLine = mock(StatusLine.class);
//and:
when(httpClient.execute(httpGet)).thenThrow(HttpHostConnectException.class);
//and:
StatusApiClient client = new StatusApiClient(httpClient, httpGet);
//when:
boolean status = client.getStatus();
//then:
Assert.assertFalse(status);
}
}
皆さんはどう思いますか、何か改善する必要がありますか? (ええ、私はコメントを知っています。それは私がスポックの背景から持ってきたものです:D)
単体テストクラスでは、defaultHttpClient
をモックする必要があります。
_@Mock
private HttpClient defaultHttpClient;
_
次に、mockitoに(たとえば_@Before
_メソッドで)次の方法で実際にモックを作成するように指示します。
_MockitoAnnotations.initMocks(YourTestClass);
_
次に、テストメソッドで、execute()
メソッドが返すものを定義します。
_when(defaultHttpClient.execute(any()/* or wahtever you want here */)).thenReturn(stubbed JSON object);
_
HttpClientMock を参照してください。内部プロジェクト用に作成しましたが、後でソースをオープンすることにしました。 Fluent APIを使用してモックの動作を定義し、後で多くの呼び出しを検証できます。例:
HttpClientMock httpClientMock = new
HttpClientMock("http://localhost:8080");
httpClientMock.onGet("/login?user=john").doReturnJSON("{permission:1}");
httpClientMock.verify().get("/login?user=john").called();
これは、final/staticメソッド、プライベートメソッド、匿名クラスを簡単にモックできるPowerMockitoを使用して簡単に行うことができます。 httpリクエストをモックするためのサンプルコードを次に示します。 JSON_STRING_DATAは、executeメソッドから取得する任意の文字列です。
PowerMockito.mockStatic(DefaultHttpClient.class);
HttpClient defaultHttpClientMocked = PowerMockito.mock(DefaultHttpClient.class);
PowerMockito.when(defaultHttpClientMocked.execute(Mockito.any(HttpPost.class))).thenReturn(createMockedHTTPResponse(JSON_STRING_DATA));
PowerMockを別の依存関係として追加することなく、これを実行するより良い方法があります。ここでは、HTTPClientを引数として、Mockitoを使用する追加のコンストラクターのみが必要です。この例では、カスタムヘルスチェック(Spring Actuator)を作成しており、ユニットテストのためにHTTPClientをモックする必要があります。
Libs:JUnit 5、Spring Boot 2.1.2、Mockito 2。
コンポーネント:
@Component
public class MyHealthCheck extends AbstractHealthIndicator {
HttpClient httpClient;
public MyHealthCheck() {
httpClient = HttpClientBuilder.create().build();
}
/**
Added another constructor to the class with an HttpClient argument.
This one can be used for testing
*/
public MyHealthCheck(HttpClient httpClient) {
this.httpClient = httpClient;
}
/**
Method to test
*/
@Override
protected void doHealthCheck(Builder builder) throws Exception {
//
// Execute request and get status code
HttpGet request = new HttpGet("http://www.SomeAuthEndpoint.com");
HttpResponse response = httpClient.execute(request);
//
// Update builder according to status code
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode == 200 || statusCode == 401) {
builder.up().withDetail("Code from service", statusCode);
} else {
builder.unknown().withDetail("Code from service", statusCode);
}
}
}
テスト方法:
ここでは、Mockito.any(HttpGet.class)を使用していることに注意してください
private static HttpClient httpClient;
private static HttpResponse httpResponse;
private static StatusLine statusLine;
@BeforeAll
public static void init() {
//
// Given
httpClient = Mockito.mock(HttpClient.class);
httpResponse = Mockito.mock(HttpResponse.class);
statusLine = Mockito.mock(StatusLine.class);
}
@Test
public void doHealthCheck_endReturns401_shouldReturnUp() throws Exception {
//
// When
when(statusLine.getStatusCode()).thenReturn(401);
when(httpResponse.getStatusLine()).thenReturn(statusLine);
when(httpClient.execute(Mockito.any(HttpGet.class))).thenReturn(httpResponse);
//
// Then
MyHealthCheck myHealthCheck = new MyHealthCheck(httpClient);
Health.Builder builder = new Health.Builder();
myHealthCheck.doHealthCheck(builder);
Status status = builder.build().getStatus();
Assertions.assertTrue(Status.UP == status);
}