SpringBootでのJUnitテストにおけるDB設定：リポジトリテストと結合テストでの違い

　SpringBootを用いたWebアプリ開発で結合テスト（以下IntegrationTest）を実施する際に、データベース周りの設定がリポジトリテスト（以下RepositoryTest）と異なり、改めてテストの設定について学習した内容を以下に記載する。

- [前提条件](#前提条件)
- [Mainでの設定](#Mainでの設定)
- [RepositoryTestでの設定](#RepositoryTestでの設定)
- [IntegrationTestでの設定](#IntegrationTestでの設定)
- [あとがき](#あとがき)

# 前提条件
### 環境
|IDE|言語|APPフレームワーク|テストフレームワーク|SQL制御|SQL|
|:---:|:---:|:---:|:---:|:---:|:---:|
|IntelliJ IDEA 2024.1.4|java 21.0.4|Spring Boot 3.3.3|JUnit 5|MyBatis 3.0.3|MySQL 8.0.39|

# Mainでの設定
　**※本題とはあまり関係ないので、[RepositoryTestでの設定](#RepositoryTestでの設定)から読んでいただくことをおススメします。**
 
　SpringBootでのSQL制御のライブラリやフレームワークにはMyBatis、Spring Data JPA、JDBC (JdbcTemplate)、Spring Data JDBCなどがあるが、今回はMyBatisを用いた場合の例であることを承知されたい。

### MyBatis
　MyBatisによるSQL制御の特徴は以下の通り。
 - 比較的軽量で高パフォーマンス
 - SQLの知識が必要
　SQLの知識が必要な点は、長所にも短所にもなり得る。SQL習得者にとっては複雑なクエリを記述できること、またコードの可読性が高くなることを意味する。一方、SQL未習得者にとってはSQLの学習コストを受け入れる必要がある（個人的にはSQLくらい勉強すべき）。
　使用するためには、build.gradleで以下を設定する。
```build.gradle
dependencies {
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
}
```

### その他の設定
#### MySQL Connector
　[MySQL 8.0 リファレンスマニュアル](https://dev.mysql.com/doc/refman/8.0/ja/connectors-apis.html#:~:text=MySQL%20Connector,-Oracle%20%E3%81%A7%E3%81%AF%E5%A4%9A%E6%95%B0&text=Connector%2FJ%20%E3%81%AF%E6%A8%99%E6%BA%96%20JDBC,%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E6%8F%90%E4%BE%9B%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)によると、JavaアプリケーションでMySQLを使用するにはMySQL Connector/Jが必要となる。
 
>Connector/J は標準 JDBC (Java Database Connectivity) API を使用して、Java アプリケーションから、MySQL に接続するためのドライバサポートを提供します。

```build.gradle
dependencies {
	runtimeOnly 'com.mysql:mysql-connector-j'
}
```
#### SQLへの接続設定
　Connector/JでJDBCを使用して指定のデータベースにアクセスする設定を追加。
```application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/database_name
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
```

#### オブジェクトマッピング
　一般的にSQLではスネークケースで命名するのに対して、Javaではキャメルケースで命名するため、両者をapplication.propertiesでマッピングする必要がある。
```application.properties
mybatis.configuration.map-underscore-to-camel-case=true
```

#### `@Mapper`
　`@Mapper`をインターフェースに付けると、そのインターフェースがSQL操作を行うクラス（マッパークラス）としてMyBatisによって認識される。
```Repository.java
@Mapper
public interface Repository {
--- 各種メソッドを記載 ---
}
```

# RepositoryTestでの設定
### `@MybatisTest`
　`@MybatisTest`を使用したクラスでは以下の3つの特徴がある。
 - **テスト環境自動構築**：`@Mapper`インターフェースを使用したデータベース関連のテストに特化しており、必要なコンポーネントのみをテスト用に起動する
 - **テスト用データベース設定**：H2などのテスト用データベースを使用するように自動的に設定される
 - **`@Transactional`サポート**：デフォルトで`@Transactional`が付与され、各テストメソッドの後にトランザクションが自動的にロールバックされる

```build.gradle
dependencies {
	testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'
}
```

```RepositoryTest.java
@MybatisTest
class FootballRepositoryTest {
--- 各種メソッドを記載 ---
}
```

### H2DB
　前述の通り、`@MybatisTest`を付加したクラスではインメモリデータベースを使用するため、そのセットアップが必要。以下はインストールおよび接続設定のみで、schema.sqlとdata.sqlによる初期データセットアップが別途必要。
 
```build.gradle
dependencies {
	testImplementation 'com.h2database:h2:2.3.232'test:3.0.3'
}
```

接続設定は、mainとは別にtest/resourcesにapplication.propertiesの作成が必要。
```application.properties
spring.datasource.url=jdbc:h2:~/test;MODE=MySQL
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driver-class-name=org.h2.Driver
spring.h2.console.enabled=true
```
# IntegrationTestでの設定
　基本設定として、`@SpringBootTest`と`@AutoConfigureMockMvc`を使用する前提で話を進める。また、データベースはRepositoryTestと同様H2DBを使用する。
 
```IntegrationTest.java
@SpringBootTest
@AutoConfigureMockMvc
class FootballIntegrationTest {
--- 各種メソッドを記載 ---
}
```

　前述の通り、`@MybatisTest`ではデータベース周りの設定を自動で設定してくれる部分が大きかった。ここで`@MybatisTest`の特徴を再掲する。
 `@MybatisTest`を使用したクラスでは以下の3つの特徴がある。
 - **テスト環境自動構築**
 - **テスト用データベース設定**
 - **`@Transactional`サポート**

　テスト環境自動構築については、IntegrationTestと関係がないのでここでは触れない。
　残りの2点について、IntegrationTestではマニュアルでの設定が必要なので、以下に説明する。

### テスト用データベース設定
　データベースに関する設定をせずにテストを実施するとエラーが発生する（詳細は不明、`@SpringBootTest`のデフォルトデータベースの問題と思うが誰か教えてください。）
　結論から言うと、`@AutoConfigureTestDatabase`によって、用いるデータベースを明示する必要がある。
```IntegrationTest.java
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureTestDatabase(replace = Replace.ANY) // 'AUTO_CONFIGURED'も可
class FootballIntegrationTest {
--- 各種メソッドを記載 ---
}
```
[`Replace`](https://spring.pleiades.io/spring-boot/api/java/org/springframework/boot/test/autoconfigure/jdbc/AutoConfigureTestDatabase.Replace.html)のオプションは以下の通り。
 - `ANY`：自動構成されたか手動で定義されたかにかかわらず、DataSource Bean を交換
 - `AUTO_CONFIGURED`：自動構成されている場合にのみ、DataSource を交換
 - `NONE`：アプリケーションのデフォルト DataSource を置き換えない

 　今回のケースでは`ANY`と`AUTO_CONFIGURED`で成功するので、デフォルトは`NONE`で設定されていると推定される。

### `@Transactional`設定
　こちらも`@MybatisTest`と異なり、自動で設定してくれないので、手動で付加する必要がある。
 ```IntegrationTest.java
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureTestDatabase(replace = Replace.ANY) // 'AUTO_CONFIGURED'も可
@Transactional
class FootballIntegrationTest {
--- 各種メソッドを記載 ---
}
```

# あとがき
　今回の記事は結合テスト時の設定とその根拠の覚書のような形でまとまった。
　テストの設定には他にも気になる部分が多いので、続けて投稿する予定。