Spring Boot + JUnit5 + DBUnitでExcelをテストデータとしたUTを行う方法

# はじめに
Spring Bootを利用したアプリケーションにおいて、
JUnit5 + DBUnitによるUTの実施方法を記載しました。

プロジェクト構成は[Spring Initializr](https://start.spring.io/)をベースとしているので、
下記を参考に、簡単に動作確認できると思います。

## インストール
動作確認にはMyBatis + Oracleを使用しました。
使用ライブラリは各環境に合わせてください。

```gradle:build.gradle
plugins {
    id 'org.springframework.boot' version '2.2.6.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
    id 'eclipse'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '12'

repositories {
    mavenCentral()
}

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.0'

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }

    // DB毎の設定をしてください
    runtime files('libs/ojdbc8.jar')

    // Lombok
    compileOnly 'org.projectlombok:lombok'


    // JUnit5
    testImplementation 'org.junit.jupiter:junit-jupiter:5.5.2'
    testImplementation 'org.junit.platform:junit-platform-commons:1.5.2'
    testImplementation 'com.github.springtestdbunit:spring-test-dbunit:1.3.0'

    // DBUnit
    testImplementation 'org.dbunit:dbunit:2.6.0'
}

test {
    useJUnitPlatform()
}
```

## テスト対象サンプル

### application.yml
Oracle向けの接続情報になるので、各DB毎に設定してください。
datasource属性にも「schema」は」存在しますが、それとは別に定義してください。
テストデータ登録時には、datasource.schemaの情報は参照されず、例外が発生してしまいます。
※Oracleだけかも知れません

```yaml:application.yml
spring:
  datasource:
    url: jdbc:oracle:thin:@localhost:1521/XEPDB1
    username: sample
    password: sample
    driverClassName: oracle.jdbc.OracleDriver
schema: SAMPLE
mybatis: 
  type-aliases-package: com.example.demo.entity
  configuration:
    map-underscore-to-camel-case: true
```
### SAMPLEテーブル
Oracle向けの...(ry

```sql
CREATE TABLE SAMPLE_TABLE 
( SAMPLE_ID NUMBER NOT NULL,
  SAMPLE_NAME VARCHAR2(255 CHAR) NOT NULL, 
  CONSTRAINT "PK_SAMPLE_TABLE" PRIMARY KEY (SAMPLE_ID)
);
```

### Entity

```java:SampleTable.java
@Data
public class SampleTable {

    private long sampleId;

    private String sampleName;
}
```

### Repository ( Mapper )

```java:SampleTableRepository.java
@Mapper
public interface SampleTableRepository {
    @Select("SELECT SAMPLE_ID, SAMPLE_NAME FROM SAMPLE_TABLE WHERE SAMPLE_ID = #{sampleId}")
    SampleTable findOne(long sampleId);
}
```

## テストクラス

### テスト用DB設定クラス
テスト実施時用のDBConfigです。
この設定クラスでデータソースとスキーマの設定を行います。

```java:DbConfig.java
@Configuration
public class DbConfig {

    @Bean(name = "dbUnitDatabaseConnection")
    public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(DataSource dataSource, @Value(value = "${schema}") String schema) {
        DatabaseDataSourceConnectionFactoryBean connectionFactory = new DatabaseDataSourceConnectionFactoryBean();
        connectionFactory.setDataSource(dataSource);
        connectionFactory.setSchema(schema);
        return connectionFactory;
    }
}
```

### Excel用ローダークラス

```java:XlsDataSetLoader.java
public class XlsDataSetLoader extends AbstractDataSetLoader {

    @Override
    protected IDataSet createDataSet(Resource resource) throws IOException, DataSetException {
        try (InputStream inputStream = resource.getInputStream()) {
            return new XlsDataSet(inputStream);
        }
    }
}

```

### テストクラス
@DbUnitConfiguration： 上記の「テスト用DB設定クラス」のデータソース、「Excel用ローダークラス」を設定してください。
@DatabaseSetup： 各テストに設定し、@DbUnitConfigurationで設定したデータソース、テストデータ、登録方法を設定してください。
※DatabaseOperationについては[こちら](https://springtestdbunit.github.io/spring-test-dbunit/apidocs/com/github/springtestdbunit/annotation/DatabaseOperation.html)を参照してください

```java:
@SpringBootTest
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionDbUnitTestExecutionListener.class, DbUnitTestExecutionListener.class })
@DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class, databaseConnection = { "dbUnitDatabaseConnection" })
public class SampleTableRepositoryTest {

    @Autowired
    SampleTableRepository sampleTableRepository;

    @Test
    @DatabaseSetup(connection = "dbUnitDatabaseConnection", value = "/testdata/findOneTest.xlsx", type = DatabaseOperation.CLEAN_INSERT)
    void データが正常に取得できること() {
        SampleTable actual = sampleTableRepository.findOne(3L);
        Assertions.assertEquals("NAME_C", actual.getSampleName(), "SAMPLE_NAMEの値が想定通りであること");
    }
}
```

## テストデータ

　シート名： テーブル名
　　１行目： カラム名
２行目以降： データ

![テストデータ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619311/257b6c75-e1da-de00-569a-f9c8e013f84a.png)

## おわりに
上記構成でテストを実行すると、ExcelのテストデータがDBに登録されます。
難点といえば、速度が遅いところでしょうか。（構成が良くないのかもしれませんが
今後はパフォーマンスの改善を目指してみようと思います。