環境
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;
}
テストコード
-
@Sql
で各テストごとのデータ作成用SQLを流す -
@Transactional
でテストメソッド毎にDBへの変更をロールバック
@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