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

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

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

ソース

AddressMapper.java

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

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

AddressMapperTests.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
@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なのか」

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

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

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

DBsetupカテゴリの最新記事