LoginSignup
1
1

More than 1 year has passed since last update.

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

Last updated at Posted at 2021-06-08

環境

  • 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については以下を参照。

テスト対象

DB接続するクラス。

@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のレコードをマッピングするエンティティ。

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

  private int id;
  private String value;
}

テストコード

@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);
  }
}
src/test/resources/infra/db/todo-delete.sql
INSERT INTO `todo` (`id`, `value`) VALUES   (1, 'delete-test');
src/test/resources/infra/db/todo-select.sql
INSERT INTO `todo` (`id`, `value`) VALUES   (1, 'select-test');
src/test/resources/infra/db/todo-update.sql
INSERT INTO `todo` (`id`, `value`) VALUES   (1, 'update-test');
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`)
);
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
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1