Spring BootのインメモリDB(H2)を使った単体テストでDBをクリーンにして各テストを実行

## 環境
- `spring boot 2.5.0`
- `mybatis-spring-boot-starter:2.2.0`
- `h2:1.4.200`

## やりたいこと
MyBatisやJPAでメソッドを定義するとき、正しくDB操作が行われているか確認したい。
Spring Bootは起動時に `shcema.sql` `data.sql` を読み込んでスキーマとデータをSQLで流すことができるが、 `data.sql` にすべてを詰め込むとどのデータがどのテスト用かわかりづらい。
なので、各テストごとにDBをクリーンな状態にしてデータを準備した後テストしたい。

`shcema.sql` `data.sql`については以下を参照。

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto.data-initialization.using-basic-sql-scripts

## テスト対象
DB接続するクラス。

``` java 
@Mapper
public interface TodoMapper {

  @Insert("INSERT INTO todo (value) VALUES (#{value})")
  @Options(useGeneratedKeys = true, keyProperty = "id")
  void insert(TodoRecord todoRecord);

  @Select("SELECT id, value FROM todo")
  List<TodoRecord> selectAll();

  @Select("SELECT id, value FROM todo WHERE id = (#{id})")
  TodoRecord selectOne(int id);

  @Update("UPDATE todo SET value = #{value} WHERE id = #{id}")
  void update(TodoRecord todoRecord);

  @Delete("DELETE FROM todo WHERE id = #{id}")
  void delete(int id);
}
```
DBのレコードをマッピングするエンティティ。

```java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TodoRecord {

  private int id;
  private String value;
}
```


## テストコード
- `@Sql` で各テストごとのデータ作成用SQLを流す
  - 参考: https://spring.pleiades.io/spring-framework/docs/current/reference/html/testing.html#spring-testing-annotation-sql
- `@Transactional` でテストメソッド毎にDBへの変更をロールバック
  - 参考: https://spring.pleiades.io/spring-framework/docs/current/reference/html/testing.html#testcontext-tx-enabling-transactions

```java
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
@Transactional
class TodoMapperTest {

  @Autowired
  private TodoMapper todoMapper;

  @BeforeEach
  void setUp() {
  }

  @Test
  void insert_success() {
    var value = "insert-test";
    var todoRecord = TodoRecord.builder()
        .value(value)
        .build();

    todoMapper.insert(todoRecord);

    var actual = todoMapper.selectAll();
    assertEquals(1, actual.size());
    assertEquals(value, actual.get(0).getValue());
  }

  @Test
  @Sql(scripts = {"classpath:/infra/db/todo-select.sql"})
  void selectAll_success() {
    var actual = todoMapper.selectAll();

    assertEquals(1, actual.size());
    assertEquals("select-test", actual.get(0).getValue());
  }

  @Test
  @Sql(scripts = {"classpath:/infra/db/todo-select.sql"})
  void selectOne_success() {
    var actual = todoMapper.selectOne(1);

    assertEquals("select-test", actual.getValue());
  }

  @Test
  @Sql(scripts = {"classpath:/infra/db/todo-update.sql"})
  void update_success() {
    var value = "updated";
    var todoRecord = TodoRecord.builder()
        .id(1)
        .value(value)
        .build();

    todoMapper.update(todoRecord);

    var actual = todoMapper.selectOne(1);
    assertEquals(value, actual.getValue());
  }

  @Test
  @Sql(scripts = {"classpath:/infra/db/todo-delete.sql"})
  void delete_success() {
    todoMapper.delete(1);

    var actual = todoMapper.selectOne(1);
    assertNull(actual);
  }
}
```

```sql:src/test/resources/infra/db/todo-delete.sql
INSERT INTO `todo` (`id`, `value`) VALUES	(1, 'delete-test');
```

```sql:src/test/resources/infra/db/todo-select.sql
INSERT INTO `todo` (`id`, `value`) VALUES	(1, 'select-test');
```

```sql:src/test/resources/infra/db/todo-update.sql
INSERT INTO `todo` (`id`, `value`) VALUES	(1, 'update-test');
```

```sql:src/test/resources/schema.sql
DROP TABLE IF EXISTS todo;

CREATE TABLE `todo` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `value` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
);
```

```yml:src/test/resources/application-default.yml
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
```