【Java】HTTP通信でHttpClientを使用してみるよ!JUnitでテストも実装してみるぜ!
Java 11 の HttpClient を使って外部システムに POST リクエストを送信する API クライアントを Gradle プロジェクトとして構築する場合、以下のステップで進めることができます
1. Gradle プロジェクトのセットアップ
build.gradleを設定します
HttpClient は Java 11 に組み込まれているため、追加の依存関係は不要ですが、依存関係として必要なライブラリがある場合はここで追加します
plugins {
id 'java'
}
group 'com.example'
version '1.0-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
// 必要に応じて他のライブラリを追加
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
test {
useJUnitPlatform()
}
2. APIクライアントの作成
次に、実際の HTTP 通信を行うクライアントクラスを作成します
今回はpost処理を実装しますね
package com.example.api.client;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
public class HttpClientService {
private final HttpClient httpClient;
public HttpClientService() {
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
}
public String sendPostRequest(String uri, String jsonPayload) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(uri))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
return response.body();
} else {
throw new RuntimeException("Failed : HTTP error code : " + response.statusCode());
}
}
}
こんな感じです(笑)
3. テストの追加
JUnit を使用してこのクライアントをテストする場合、モックを利用して外部システムに依存しないテストを書くと良いですね
(実際につなげてしまうと良くないことが起こりうる。。。)
その場合、Mockito などのモックライブラリを使用します!
送信されるリクエストの URL、リクエストボディ、ヘッダーなども検証していきます
package com.example.api.client;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
class HttpClientServiceTest {
@Test
void testSendPostRequest() throws Exception {
// モックの準備
HttpClient mockClient = mock(HttpClient.class);
HttpResponse<String> mockResponse = mock(HttpResponse.class);
// モックの戻り値設定
when(mockResponse.statusCode()).thenReturn(200);
when(mockResponse.body()).thenReturn("Success");
when(mockClient.send(any(HttpRequest.class), any(HttpResponse.BodyHandler.class)))
.thenReturn(mockResponse);
// テスト対象のサービスをモック HttpClient で初期化
HttpClientService clientService = new HttpClientService(mockClient);
String url = "https://api.example.com/resource";
String jsonPayload = "{\"key\": \"value\"}";
// 実際にメソッドを呼び出す
String response = clientService.sendPostRequest(url, jsonPayload);
// 戻り値の確認
assertEquals("Success", response);
// ArgumentCaptor を使って送信されたリクエストをキャプチャ
ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
verify(mockClient).send(requestCaptor.capture(), any(HttpResponse.BodyHandler.class));
// キャプチャしたリクエストを検証
HttpRequest capturedRequest = requestCaptor.getValue();
// 送信されたリクエストの URL を確認
assertEquals(URI.create(url), capturedRequest.uri());
// 送信されたリクエストのボディを確認
assertTrue(capturedRequest.bodyPublisher().isPresent());
HttpRequest.BodyPublisher bodyPublisher = capturedRequest.bodyPublisher().get();
assertEquals(jsonPayload, new String(bodyPublisher.contentLength() > 0
? bodyPublisher.toString() : ""));
// 送信されたリクエストのヘッダーを確認
assertEquals("application/json", capturedRequest.headers().firstValue("Content-Type").orElse(""));
}
}
ポイント
- ArgumentCaptor を使用して、HttpRequest オブジェクトをキャプチャし、モックが呼び出されたときに実際に送信されたリクエストの内容を取得します
- verify() を使って、HttpClient.send() メソッドが呼び出されたことを確認します
- キャプチャしたリクエストの検証: キャプチャしたリクエストから URL、ヘッダー、ボディを取得し、予想される値と一致するかどうかを検証します
注意点
- HttpRequest の BodyPublisher はストリームとしてデータを送信するため、テスト中では単純に文字列として扱うのが難しいです。。。
- Mockito を使うことで、テスト対象が外部システムに依存せずにテストできるため、安定したテストを実現できます
この方法で、送信されるリクエストの中身 (URL、ヘッダー、ボディ) を確認できるテストを実行できます
参考程度に…
BodyPublisher から文字列を取るには以下を参考にすると良いかもしれないです
参考程度にご覧ください
// リクエストボディの内容を確認するための実装
HttpRequest.BodyPublisher bodyPublisher = capturedRequest.bodyPublisher().orElseThrow();
// ByteArray を使ってボディの内容をキャプチャ
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bodyPublisher.subscribe(new Flow.Subscriber<ByteBuffer>() {
@Override
public void onSubscribe(Flow.Subscription subscription) {
subscription.request(Long.MAX_VALUE);
}
@Override
public void onNext(ByteBuffer byteBuffer) {
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
outputStream.write(bytes, 0, bytes.length);
}
@Override
public void onError(Throwable throwable) {}
@Override
public void onComplete() {}
});
// キャプチャされたボディの内容を文字列として取得
String capturedBody = outputStream.toString(StandardCharsets.UTF_8);
// ボディが期待通りの JSON かを確認
assertEquals(jsonPayload, capturedBody);
是非参考にしてみてください!
是非フォローしてください
最新の情報をお伝えします