Java
Kotlin
spring
spring-boot
SpringBoot

Spring Boot @DataJpaTestを使ったJPAエンティティとリポジトリのテスト

@DataJpaTestとは

エンティティとリポジトリのテストを行うためのAuto Configuratinを使用するためのアノテーション。これを使用することで簡単にテストを記述することができる。
以下のような特徴がある。
@Entitiy, @Repositoryを付与したクラスをApplicationContextへロードする。その他の@Serviceなどを付与したクラスはロードされない。
・テスト(@Test)ごとにトランザクションをロールバックする。トランザクション制御は変更可能。
・テストではインメモリDBを使用する

また、テストクラス内でテストデータを操作するためにTestEntityManagerが用意されている。

詳しくは公式ドキュメント参照。
43.3.11 Auto-configured Data JPA Tests

JPAとテスト時にH2データベースを使用するための依存関係をbuild.gradleに追加する。

build.gradle
dependencies {

    ・・・
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile group: 'com.h2database', name: 'h2', version: '1.4.197'
}

サンプルとして、以下のように書籍情報を扱うエンティティとリポジトリを作成する。以下の例はKotlinで記述しているがJavaでも記述方法は同じ。

@Entity
@Table(name = "book")
data class Book(

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY) // IDは自動生成する
        @Column(name = "id")
        var id: Long = 0,

        @Column(name = "title")
        var title: String = "",

        @Column(name = "author")
        var author: String = "",

        @Column
        var price: Long = 0
)

上記エンティティに対して以下のリポジトリを作成する。

@Repository
interface BookRepository: JpaRepository<Book, Long> {

    // 指定されたauthorのbookのリストをpriceの昇順で返すメソッド
    fun findAllByAuthorOrderByPrice(author: String): List<Book>
}

テストクラスを作成する。TestEntityManagerを使うことでRepositoryを使用せずにテストデータをDBに格納できる。

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
import org.springframework.test.context.junit4.SpringRunner

@RunWith(SpringRunner::class)
@DataJpaTest
class BookRepositoryTest {

    @Autowired
    private lateinit var testEntityManager: TestEntityManager

    @Autowired
    private lateinit var bookRepository: BookRepository

    @Test
    fun test() {

        // テストデータ作成
        testEntityManager.persist(Book(title = "title1", author = "author1", price = 102))
        testEntityManager.persist(Book(title = "title2", author = "author1", price = 101))
        testEntityManager.persist(Book(title = "title3", author = "author2", price = 104))
        testEntityManager.persist(Book(title = "title4", author = "author2", price = 103))

        val foundBooks = bookRepository.findAllByAuthorOrderByPrice("author1")

        // author1のbookは2つ
        assertThat(foundBooks).size().isEqualTo(2)

        // 検索結果は価格の昇順なので、title2, title1 の順になっているはず
        // title1
        assertThat(foundBooks[0].id).isEqualTo(2)
        assertThat(foundBooks[0].title).isEqualTo("title2")
        assertThat(foundBooks[0].author).isEqualTo("author1")
        assertThat(foundBooks[0].price).isEqualTo(101)

        // title2
        assertThat(foundBooks[1].id).isEqualTo(1)
        assertThat(foundBooks[1].title).isEqualTo("title1")
        assertThat(foundBooks[1].author).isEqualTo("author1")
        assertThat(foundBooks[1].price).isEqualTo(102)

    }
}