目的
APIテストを自動化したいなーという思いからテストツールを調べていたので、その流れで調査とかPoCをやってきた過程をメモがてら残していきます。
この記事では基礎編として下記を取り扱います。
- REST Assuredを使ったシンプルなGETメソッドのテスト
- リクエストを別ファイルで作成したPOSTメソッドのテスト
- DBをJUnitでつないでAPIのレスポンスとSQLクエリとのレスポンスを比較する
REST Assuredとは
詳細は公式見ていただくとしてざっくり言ってしまえばREST APIのテストをできるJavaに組み込めるツールです。
なので、Intellijからテストを実行できたり作ったりするのが容易です。
公式サイトもあり分かりやすいことが書いてあるので詳細はこちらから。
https://rest-assured.io/
実行環境
- Windows 11
- Java 17
- REST Assured 5.5.0
- Junit 5.10.3
- Spring boot 3.3.4
Mavenを使っているのでは下記を設定しています。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
</dependencies>
GETメソッドのテスト
愚直に書いてみよう
REST Assuredではgiven/when/thenの形式でテストを記述することができます。
ここではこういう感じで使います。
- given
- ホストネームの指定
- headerの指定
- when
- エンドポイントの呼び出し
- then
- テスト結果の比較
package testcase;
import client.ApiClient;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
public class Step1_FieldAssertionTest {
@Test
void should_match_nested_fields() {
String path = "http://localhost:8080/users/1";
given()
.contentType("application/json")
.accept("application/json")
.when()
.get(path)
.then()
.log().ifValidationFails()
.statusCode(200)
.body("userId", equalTo(1))
.body("firstName", equalTo("yamada"))
.body("lastName", equalTo("taro"));
}
}
whenのget(path)がget methodへのりくえすとを粟原している形です。メソッドごとにあるのは非常にわかりやすいなと思います。
では、テストを実行します。
まずはアプリケーションを立ち上げます。

「1件のテストが合格しました」と出ているので、これでテストが通ったことが確認できました。

拡張性を持たせてみよう
上記の形で書いていくとテストケースが増えてくると2つの問題が出てきます。
- givenで設定するヘッダー情報が重複する -> DRY原則に反する
- host名がべた書きされているので、環境別の変更に弱い
そこで、これらの問題を解決するApiClientクラスを作ります。
package client;
import io.restassured.RestAssured;
import io.restassured.config.LogConfig;
import io.restassured.specification.RequestSpecification;
import static io.restassured.RestAssured.given;
public class ApiClient {
// BASE_URIを設定することでhost名を共通で扱えます。
private static String baseUrl() {
String env = System.getenv("BASE_URL");
return (env == null || env.isBlank()) ? "http://localhost:8080" : env;
}
static {
RestAssured.baseURI = baseUrl();
RestAssured.config = RestAssured.config()
.logConfig(LogConfig.logConfig().enableLoggingOfRequestAndResponseIfValidationFails());
}
// givenの共通項目の指定
public static RequestSpecification req() {
return given()
.contentType("application/json")
.accept("application/json");
}
}
ではこれを使って書き直すと下記のようになります。
package testcase;
import client.ApiClient;
import org.junit.jupiter.api.Test;
import static org.hamcrest.Matchers.*;
public class Step1_GetFieldAssertionTest {
@Test
void should_match_nested_fields() {
String path = "/users/2";
ApiClient.req()
.when()
.get(path)
.then()
.log().ifValidationFails()
.statusCode(200)
.body("userId", equalTo(2))
.body("firstName", equalTo("yamada"))
.body("lastName", equalTo("hanako"));
}
}
最初のべた書きの場合に比べてインデントは深くなりましたがgiven().~がApiClient.req()に集約されてダイエットされました。
今の時点では1つのエンドポイントを見ているので、あまり意味はないですが、テストケースが増えると聞いてきます。
つまり次の章からはこれを導入していきます。
実行結果はこちらです。
下記は流す前に検証必要
下記の記事ではgiven時にprettyprintを設定しておりその方が見やすいかと思います。
参考:https://qiita.com/shimashima35/items/b85228d5bf5ec2708c5a
POSTメソッドのテスト
愚直に書いてみよう
GETと変わる箇所は以下です。
- given
- body リクエストボディーの指定
- when
- post
では愚直にrequestBodyに突っ込むjsonをコードにべた書きしてpostしてみましょう。
package testcase;
import client.ApiClient;
import org.junit.jupiter.api.Test;
import static org.hamcrest.Matchers.*;
public class Step2_PostFieldAssertionTest {
@Test
void should_register_user() {
String path = "/users/register";
String requestBody = """
{
"firstName": "yamada",
"lastName": "hanako",
"password": "test1234!"
}
""";
ApiClient.req()
.body(requestBody)
.when()
.post(path)
.then()
.log().ifValidationFails()
.statusCode(200)
.body("userId", notNullValue())
.body("firstName", equalTo("yamada"))
.body("lastName", equalTo("hanako"));
}
}
拡張性を持たせてみよう
上記のテストはstring型でリクエストjsonをべた書きしています。
この形だと、仮にこのリクエストjsonをほかでも使いたいとかの事例が出てきたり、したときに再利用できません。
また、コードの中にリクエストjsonがあるのでコード自体が長くなって読みづらくなります。
では、次にjsonファイルを作ってそれを読み込む形にしてみましょう。
プロジェクトルートディレクトリのsrc/test配下は下記のような構造になります
C:.
├─client
│ ApiClient.java
│
├─resources
│ │ application-test.properties
│ │
│ └─request
│ success_user_register.json
│
└─testcase
Step1_GetFieldAssertionTest.java
Step2_PostFieldAssertionTest.java
package testcase;
import client.ApiClient;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import static org.hamcrest.Matchers.*;
public class Step2_PostFieldAssertionTest {
@Test
void should_register_user() throws IOException {
String path = "/users/register";
InputStream is = getClass().getClassLoader()
.getResourceAsStream("request/success_user_register.json");
String requestBody = new String(is.readAllBytes(), StandardCharsets.UTF_8);
ApiClient.req()
.body(requestBody)
.log().all()
.when()
.post(path)
.then()
.log().all()
.statusCode(200)
.body("userId", notNullValue())
.body("firstName", equalTo("yamada"))
.body("lastName", equalTo("hanako"));
}
}
ついでに今回はすべてのログを出すように変えてみたので、そのログも見てみます。

ログはこのようになっておりPOST時のリクエストボディーとレスポンスの値がちゃんとあることが分かります。
Request method: POST
Request URI: http://localhost:8080/users/register
Proxy: <none>
Request params: <none>
Query params: <none>
Form params: <none>
Path params: <none>
Headers: Accept=application/json
Content-Type=application/json
Cookies: <none>
Multiparts: <none>
Body:
{
"firstName": "yamada",
"lastName": "hanako",
"password": "test1234!"
}
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 11 Apr 2026 01:04:36 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"firstName": "yamada",
"lastName": "hanako",
"userId": 36
}
番外編(間違った値で比較してみる)
せっかくなので、間違えてみましょう。
assert側のfirstNameをkagawaにlastNameをdaichiにしましょう。

ログを見てみるとfirstNameは期待値と実際の値を出してくれていますね。
一方でlastNameは後に検証しているので出ていません。
全部出すという方向にする場合はJunit側でassertAllを使って比較をするとできます。
結果はこんな感じです。

Junitで全部比較する場合のコード
package testcase;
import client.ApiClient;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class Step2_PostFieldAssertionTest {
@Test
void should_register_user() throws IOException {
String path = "/users/register";
InputStream is = getClass().getClassLoader()
.getResourceAsStream("request/success_user_register.json");
String requestBody = new String(is.readAllBytes(), StandardCharsets.UTF_8);
Response response = ApiClient.req()
.body(requestBody)
.log().all()
.when()
.post(path);
String firstName = response.jsonPath().getString("firstName");
String lastName = response.jsonPath().getString("lastName");
assertAll(
() -> assertEquals(200, response.statusCode()),
() -> assertEquals("kagawa", firstName),
() -> assertEquals("daichi", lastName)
);
}
}
最後に
このテストのPoC記事は後2つ書くつもりで、残りは応用編とシナリオテスト編です。
今回でRPGで言うと最低限の操作コマンドを覚えた感じなので、応用編はレベルアップして技を覚えていく感じになります。
シナリオテスト編はその技を駆使してよりうまく戦っていこうというような算段です。


