SpringTestとJUnit5でMyBatisのMapperをテストする

# SpringTestとJUnit5でMyBatisのMapperをテストする
## はじめに
### 概要
SpringMVCを使用したマルチモジュールプロジェクトでMybatisのMapperをテストした際のメモです.
#### モジュール構成
以下のようなモジュール構成になっています. 以下のモジュールのうち`domain`モジュールにMybatisのMapperクラスがあります.

```
root
|- web
|- application
|- domain
```

#### domainモジュールの構成
```
domain
|- domain.entity
|- domain.mapper
|- domain.service
```

#### テスト対象
`domain.mapper.SampleMapper.java`の`insert(Sample sample)`メソッドをテストします.
指定したデータが登録されたかを確認するだけのシンプルなテストです.
ここではテスト設計の仕方などは説明を省きます.

### バージョン
+ SpringFramework 5.1.5.RELEASE
+ Mybatis 3.4.1
+ Mybatis Spring 2.0.0
+ JUnit-jupiter 5.4.0
+ SpringFramework Test 5.1.6.RELEASE

## やり方
[Spring5入門[簡単なWebアプリのユニットテストをJUnit5とJMockitで作成]](https://javaworld.helpfulness.jp/post-333/)を参考にしました.
### 1.テストコードの作成
いつも通りテストコードを作成します.

```SampleMapperTest.java
class SampleMapperTest{

	@Autowired
	private SampleMapper mapper;
	
	@Test
	void test() {
		try{
			String testName = "testName";
			String testPass = "testPass";

			Sample testData = prepare(testName, testPass);
			insert(testData);
			Integer id = testData.getId();
			Sample registeredData = searchOf(id);
			validate(testName, testPass, registeredData);
		} catch (Exception e) {
			deleteDataOf(id);
		}
	}
	
	Sample prepare(String testName, String testPass) {
		Sample sample = new Sample();
		sample.setName(testName);
		worker.setPassword(testPass);
		return worker;
	}
	
	void insert(Sample testData) {
		mapper.insertSelective(testData);
	}
	
	Sample searchOf(Integer id) {
		return mapper.selectByPrimaryKey(id);
	}
	
	void deleteDataOf(Integer id) {
		mapper.deleteByPrimaryKey(id);
	}

	void validate(String expectedName, String expectedPass, Sample actual) {
		assertNotNull(actual);
		Sample expected = new Sample();
		expected.setId(actual.getId());
		expected.setPassword(expectedName);
		expected.setPassword(expectedPass);
		assertEquals(expected, actual);
	}

}
```

### テスト用のapplication-context.xmlを設定
このままだとSampleMapperにインスタンスがインジェクションされません.
テスト用の設定にコンポーネントの設定などを定義します.
テスト用の設定は, 特にこだわりがなければ本番用の設定をそのまま使ってもOKです.
今回は`src/test/resources/META-INF/`に`test-context.xml`を定義します.

``` test-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
		
	<!-- component scan -->
	<context:component-scan base-package="domain" />

	<!-- database info -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.postgresql.Driver" />
		<property name="url" value="jdbc:postgresql://localhost/sample" />
		<property name="username" value="postgres" />
		<property name="password" value="postgres" />
	</bean>
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:mybatis-config.xml" />
	</bean>
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- scan mappers for mybatis -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="domain.mapper" />
	</bean>
</beans>
```

また, 手順1で作成したテストクラスに`@SpringJUnitConfig`アノテーションを付与します.
`@SpringJUnitConfig`アノテーションの引数には, テスト用の設定ファイルを指定します.

```SampleMapperTest.java
@SpringJUnitConfig(location = "classpath:META-INF/test-context.xml")
class SampleMapperTest{
// 以下略
```

### 3. テスト実行
ここまででテストの準備が整ったので, テストを実行します.
テストを実行すると, テスト用の設定ファイルの記述をもとに, Springのコンポーネントが生成され, テストが行われるのが分かります.

## 参考サイト
[Spring5入門\[簡単なWebアプリのユニットテストをJUnit5とJMockitで作成\]](https://javaworld.helpfulness.jp/post-333/)