【Spring Boot】【MyBatis】【DBSetup】Repository層(Mapper)の単体Test実装方法

【Spring Boot】【MyBatis】【DBSetup】Repository層(Mapper)の単体Test実装方法

Spring BootにおけるRepository層に対する単体テスト

ソース

AddressMapper.java

@Select("SELECT * FROM address WHERE city_id = #{cityId}")
Set<Address> findAddress(@Param("cityId") int cityId);

複数のデータが返ってくるようなSQLです。

AddressMapperTests.java

@MybatisTest
public class AddressMapperTests {

    @Autowired
    private AddressMapper target;

    @Autowired
    private DataSource dataSource;


    private final Operation RESET_DATA = Operations.deleteAllFrom("address");

    private void dbSetup(Operation operation) {
        Destination destination = new DataSourceDestination(dataSource);
        DbSetup dbSetup = new DbSetup(destination, operation);
        dbSetup.launch();
    }

    @BeforeEach
    void setUp() {
        dbSetup(Operations.sequenceOf(
                RESET_DATA
        ));
    }

    @AfterEach
    void tearDown() {
        dbSetup(Operations.sequenceOf(
                RESET_DATA
        ));
    }
	
    @DisplayName("データ検証テスト")
    @Nested
    class FieldValue {

        private final Operation INSERT_ADDRESS_DATA = Operations.insertInto("address")
                .columns("address_id", "address", "district", "city_id", "phone", "last_update")
                .values(1, "fashion 109", "Shibuya", 1, "28303384290", "2012-01-01 12:12:00")
                .values(2, "salary 999", "Shinbashi", 1, "635297277345", "2012-01-02 12:12:00")
                .build();

        @BeforeEach
        void setUp() {
            dbSetup(INSERT_ADDRESS_DATA);
        }

        @DisplayName("Setに含まれる要素をまとめて検証する")
        @Test
        void dataValueTest() {

            //GIVEN
            int cityId = 1;

            //WHEN
            Set<Address> actual = target.findAddress(cityId);

            //THEN
            assertThat(actual).extracting("addressId").allMatch(i -> Arrays.asList(1, 2).contains(i));
            assertThat(actual).extracting("address").allMatch(i -> Arrays.asList("fashion 109", "salary 999").contains(i));
            assertThat(actual).extracting("address2").allMatch(Objects::isNull);
            assertThat(actual).extracting("district").allMatch(i -> Arrays.asList("Shibuya", "Shinbashi").contains(i));
            assertThat(actual).extracting("postalCode").allMatch(Objects::isNull);
            assertThat(actual).extracting("phone").allMatch(i -> Arrays.asList("28303384290", "635297277345").contains(i));
            assertThat(actual).extracting("lastUpdate").allMatch(i -> Arrays.asList(
                    LocalDateTime.parse("2012-01-01 12:12:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                    LocalDateTime.parse("2012-01-02 12:12:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
            ).contains(i));
        }
    }
}

解説

解説したいところは2点あります。

@MybatisTest

@MybatisTestを使用することで、MybatisによるSQL実行に必要なコンポーネントのみを読み込んでくれるので、リソースが必要最小限で済みます。
@SpringBootTestでも動くのですが、@SpringBootTestの場合はプロジェクトのコンポーネント全てを読み込んでしまうので、Testに時間がかかります。

Collection型のオブジェクトの中身をまとめて検証する

THENで検証しているところで、Set型のオブジェクトの中身をまとめて検証しています。
List型では順番にfor文でオブジェクトを取り出して値を一つ一つ検証するということも可能ですが、Set型は順序性が担保されていないため、一つ一つ取り出して検証ということが出来ません。
そういった時に「それぞれのオブジェクトの中にどんな値が入っていればOKなのか」を示してあげて、一致すればOKという感じでテストしています。

「それぞれのオブジェクトの中にどんな値が入っていればOKなのか」

assertThat(actual).extracting("phone").allMatch(i -> Arrays.asList("28303384290", "635297277345").contains(i));

「それぞれのオブジェクトの中に何も入ってなければOK」

assertThat(actual).extracting("address2").allMatch(Objects::isNull);

DBsetupカテゴリの最新記事