Spring Boot + MySQLでシンプルなWeb REST APIサーバを実装する - Qiita
Outline
Spring bootで作成したREST APIの機能テストをやる。
httpリクエストを送信し、レスポンスと、DBの状態をテストする。
インメモリDB(H2)を利用することで、DBサーバが無くても実行可能なテストを組む。
H2
準備
dependency
プロジェクトの依存にH2を追加する。
testCompile("com.h2database:h2:${h2Version}")
接続設定
src/test/resources/application.yml
ここに置くことで、テスト時に読み込まれるprofileを定義できる。
テスト時はMySQLではなく、H2の設定を書く。
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:;DB_CLOSE_ON_EXIT=TRUE;MODE=MySQL
username: sa
password:
jpa:
hibernate:
ddl-auto: none
DDL
src/test/resources/schema.sql
Spring Bootアプリケーションでは、schema.sqlというファイル名のスクリプトは起動時に実行される。
DDLを書いておく。
CREATE TABLE IF NOT EXISTS test_users (
id VARCHAR(18) NOT NULL
, value VARCHAR(255) DEFAULT NULL
, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
, PRIMARY KEY(id)
);
DML
src/test/resources/data.sql
schema.sql同様、data.sqlというファイルも起動時に実行される。
テストに利用するデータを起動時に挿入しておく。
INSERT INTO test_users ( id, value ) VALUES ( 'test_id', 'test_value' );
UserApiTests.java
ユーザ登録のテストのみ抜粋
︙
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserApiTests {
private final static String TABLE = "test_users";
private static final String SELECT_SQL = String.format("SELECT * FROM %s WHERE ID = ?", TABLE);
private static final String BASE_PATH = "/v1/users/";
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TestRestTemplate testRestTemplate;
@Test
public void postUser() throws URISyntaxException {
String body = "{\"id\":\"test_post_id\",\"value\":\"test_post_value\"}";
String exceptedResp = body;
RequestEntity req = RequestEntity
.post(new URI(BASE_PATH))
.header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
.body(body);
ResponseEntity actualResp = this.testRestTemplate.exchange(req, String.class);
assertThat(actualResp.getBody().toString()).isEqualTo(exceptedResp);
assertThat(actualResp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
Map<String, Object> actualData = this.jdbcTemplate.queryForMap(SELECT_SQL, "test_post_id");
assertThat(actualData.get("id")).isEqualTo("test_post_id");
assertThat(actualData.get("value")).isEqualTo("test_post_value");
}
︙
SpringBootTest
@SpringBootTestを付与することで、Springアプリケーションが起動する。
これにより、DIコンテナなどSpringの機能が利用可能となる。
そのぶんテスト実行に時間がかかるので単体テストとかでペタペタ貼らないほうがいい気がする。
Http通信部分
@SpringBootTestの引数を以下のように設定することで、空いているポートでWebサーバが起動する。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
このポートにアクセスする方法はいくつかあるが、今回はTestRestTemplateを使う
インタフェースなどRestTemplateとほぼ変わらない。
指定するURIにホスト名などを含めず、ベースパス以降にするだけで、テスト用に立ちたがっているアプリケーションと通信する。
Spring Boot Reference Guide
インスタンスはDIコンテナ経由で取得可能。
@Autowired
private TestRestTemplate testRestTemplate;
DB部分
JdbcTemplateを利用して、DBの状態を取得する。
これもDIコンテナ経由でインスタンスが取得可能。
queryForMapというインタフェースでMap形式でレコードを参照可能。
Map<String, Object> actualData = this.jdbcTemplate.queryForMap(SELECT_SQL, "test_post_id");
assertThat(actualData.get("id")).isEqualTo("test_post_id");
assertThat(actualData.get("value")).isEqualTo("test_post_value");
ちなみに0件をnullとかでチェックすることはできないようなので、そういうときはListを使ってる。
List<Map<String, Object>> actualDataList = this.jdbcTemplate.queryForList(SELECT_SQL, "test_empty_id");
assertThat(actualDataList.size()).isEqualTo(0);