【Spring Boot】JunitでRepositoryの単体テストを行う

【Spring Boot】JunitでControllerの単体テストを行う バックエンド
スポンサーリンク

はじめに

ぴんくうさぎ
ぴんくうさぎ

Repositoryの実装ができたけど、テストコードが全然書けません!
実際にDBにデータを流してテストしたいの!

みどりがめ
みどりがめ

OK!今回はRepositoryクラスのテストコードの書き方を勉強していこう!

今回はJUnit5を使用したRepositoryクラスのテストコードの記述方法を紹介します。なお、実装はSpring Boot、MyBatisを使用しています。で行っています。

そもそも、Junitの基本的な使い方がわからない方は以下の記事を参考にしてください!

また、私自身がJUnitを学習する際には、以下の書籍にお世話になりました。
JUnitの参考書としては頭一つ抜けて人気で王道書籍です。
基本的なところから丁寧に解説されていて、非常に分かりやすいです。これからJUnitを学習する方におすすめです。

サンプルコード

テスト対象クラス

今回のサンプルにおけるテスト対象クラスは以下のRepositoryクラスです。
ユーザー情報を扱うリポジトリクラスで以下の2つのメソッドをテスト対象とします。

  • register()・・・ユーザーを登録する
  • findByEmailAndPassword・・・ユーザー名とパスワードでユーザーを検索する
 /**
 * ユーザー情報を扱うリポジトリ.
 */
@Repository
@AllArgsConstructor
public class UserRepository {

    private final UserBaseMapper userBaseMapper;

    /**
     * 登録する.
     *
     * @param user 登録するユーザー
     * @return 登録したユーザー
     */
    public User register(User user) {
        UserBase base = User.fromModel(user);
        userBaseMapper.insert(base);
        return User.fromBase(base);
    }

    /**
     * 検索する(メールアドレス&パスワード)
     * @param email メールアドレス
     * @param password パスワード
     * @return 検索結果
     */
    public List<User> findByEmailAndPassword(String email,String password) {
        UserBaseExample criteria = new UserBaseExample();
        criteria.createCriteria()
                .andEmailEqualTo(email)
                .andPasswordEqualTo(password)
                .andDeleteFlgEqualTo(DeleteFlg.FLG_OFF.getValue());

        return User.fromBaseList(userBaseMapper.selectByExample(criteria));
    }

}

テストクラス

Repositoryクラスに対するテストクラスは以下のようになります。
赤字箇所の重要ポイントについて以下で説明します。

// (1)
@SpringBootTest
// (2)
@Transactional
@Sql("classpath:sql/user-repository.sql")
class UserRepositoryTest {

    @Autowired
    UserRepository userRepository;

    @Autowired
    UserBaseMapper userBaseMapper;

// (3)
    @Test
    @DisplayName("register_正常系")
    void register() {
    
        // データの準備
        UserBase userBase = new UserBase();
        userBase.setId(1L);
        userBase.setFirstName("register");
        userBase.setLastName("次郎");
        userBase.setAge(45);
        userBase.setTel("000-1234-5679");
        userBase.setAddress("次郎のお家");
        userBase.setEmail("jiro@gmail.com");
        userBase.setPassword("jirodayo");
        User user = User.fromBase(userBase);

        // テストの実行
        User actual = userRepository.register(user);

        // 結果の検証
        UserBaseExample criteria = new UserBaseExample();
        criteria.createCriteria()
                .andFirstNameEqualTo("register")
                .andLastNameEqualTo("次郎")
                .andEmailEqualTo("jiro@gmail.com")
                .andDeleteFlgEqualTo(DeleteFlg.FLG_OFF.getValue());
        assertEquals(1, userBaseMapper.selectByExample(criteria).size());

        assertEquals("register", actual.getFirstName());
        assertEquals("次郎", actual.getLastName());
        assertEquals(45, actual.getAge());
        assertEquals("000-1234-5679", actual.getTel());
        assertEquals("次郎のお家", actual.getAddress());
        assertEquals("jiro@gmail.com", actual.getEmail());
        assertEquals("jirodayo", actual.getPassword());
    }

    @Test
    @DisplayName("findByEmailAndPassword_正常系")
    void findByEmailAndPassword() 

        // テストの実行
        List<User> actual = userRepository
                .findByEmailAndPassword("test2@gmail.com", "PASSWORD2");

        // 結果の検証
        assertEquals(1, actual.size());
        assertEquals(102L, actual.get(0).getId());
        assertEquals("FIRST_NAME", actual.get(0).getFirstName());
        assertEquals("LAST_NAME", actual.get(0).getLastName());
        assertEquals(10, actual.get(0).getAge());
        assertEquals("090-1234-5678", actual.get(0).getTel());
        assertEquals("ADDRESS", actual.get(0).getAddress());
        assertEquals("test2@gmail.com", actual.get(0).getEmail());
        assertEquals("PASSWORD2", actual.get(0).getPassword());
    }
}

user-repository.sqlの中身は以下のなります。

INSERT INTO users
(id, first_name, last_name, age, tel, address, email, password, created_at, updated_at, delete_flg) VALUES

--findByEmailAndPassword
(102, 'FIRST_NAME', 'LAST_NAME', 10, '090-1234-5678', 'ADDRESS', 'test2@gmail.com', 'PASSWORD2', '2023-02-19 10:47:19', '2023-02-19 10:47:19', 0),
--ダミーデータ
(103, 'FIRST_NAME', 'LAST_NAME', 10, '090-1234-5678', 'ADDRESS', 'test2@gmail.com', 'PASSWORD1', '2023-02-19 10:47:19', '2023-02-19 10:47:19', 0),
(104, 'FIRST_NAME', 'LAST_NAME', 10, '090-1234-5678', 'ADDRESS', 'test2@gmail.com', 'PASSWORD2', '2023-02-19 10:47:19', '2023-02-19 10:47:19', 1)
;

(1)@SpringBootTestの付与

@SpringBootTestはテスト環境でもSpring Frameworkの機能を使用するためのアノテーションです。
通常の@TestではDIコンテナが動作せず、自動でインスタンス化されないため本アノテーションをつける必要があります。

公式はこちら

(2)@Sql、@Transactionの付与

@Sqlを付与すると、引数のファイルパスのsqlをテスト実行時に流すことができます。
今回の場合、findByEmailAndPasswordで取得するためのテストデータを事前にinsertしています。(ローカル環境のDBに接続されていることが前提条件です。)

@Transactionalを付与すると、処理が終わるとデフォルトでロールバックが実行されるようになります。つまり、@Sqlでinsertしたものをロールバックしてくれます。

@Transactional
@Sql("classpath:sql/user-repository.sql")

(3)実際のテストメソッド

テストメソッド自体は、JUnitの基礎がわかれば理解しやすいと思います。

まずはregisterから解説します。
「データの準備」でinsertするユーザーの情報を準備しています。
「テストの実行」で、テスト対象のメソッドを使用しています。
「結果の検証」でDBのデータを取得し、一つ一つのプロパティの検証を行っています。

      @Test
    @DisplayName("register_正常系")
    void register() {
    
        // データの準備
        UserBase userBase = new UserBase();
        userBase.setId(1L);
        userBase.setFirstName("register");
        userBase.setLastName("次郎");
        userBase.setAge(45);
        userBase.setTel("000-1234-5679");
        userBase.setAddress("次郎のお家");
        userBase.setEmail("jiro@gmail.com");
        userBase.setPassword("jirodayo");
        User user = User.fromBase(userBase);

        // テストの実行
        User actual = userRepository.register(user);

        // 結果の検証
        UserBaseExample criteria = new UserBaseExample();
        criteria.createCriteria()
                .andFirstNameEqualTo("register")
                .andLastNameEqualTo("次郎")
                .andEmailEqualTo("jiro@gmail.com")
                .andDeleteFlgEqualTo(DeleteFlg.FLG_OFF.getValue());
        assertEquals(1, userBaseMapper.selectByExample(criteria).size());

        assertEquals("register", actual.getFirstName());
        assertEquals("次郎", actual.getLastName());
        assertEquals(45, actual.getAge());
        assertEquals("000-1234-5679", actual.getTel());
        assertEquals("次郎のお家", actual.getAddress());
        assertEquals("jiro@gmail.com", actual.getEmail());
        assertEquals("jirodayo", actual.getPassword());
    }

次にfindByEmailAndPasswordです。
「データの準備」はテスト実行前の@sqlの実行で済んでいます。
「テストの実行」で、テスト対象のメソッドを使用しています。
「結果の検証」でテスト実行結果のオブジェクトから一つ一つのプロパティの検証を行っています。

    @Test
    @DisplayName("findByEmailAndPassword_正常系")
    void findByEmailAndPassword() 

        // テストの実行
        List<User> actual = userRepository
                .findByEmailAndPassword("test2@gmail.com", "PASSWORD2");

        // 結果の検証
        assertEquals(1, actual.size());
        assertEquals(102L, actual.get(0).getId());
        assertEquals("FIRST_NAME", actual.get(0).getFirstName());
        assertEquals("LAST_NAME", actual.get(0).getLastName());
        assertEquals(10, actual.get(0).getAge());
        assertEquals("090-1234-5678", actual.get(0).getTel());
        assertEquals("ADDRESS", actual.get(0).getAddress());
        assertEquals("test2@gmail.com", actual.get(0).getEmail());
        assertEquals("PASSWORD2", actual.get(0).getPassword());
    }

終わりに

本記事はここまでとなります。
ご覧いただきありがとうございました。ご指摘等がございましたら頂けますと嬉しいです。

以下の記事ではControllerの単体テストについて記載しています。よろしければ併せてご覧ください。


引き続き、プログラミングについて定期的に発信していきますのでよろしくお願いします!
また、もしよろしければtwitterもフォローしていただけると嬉しいです!🐢

コメント