Help us understand the problem. What is going on with this article?

SpringMockKを使ってみた

kotlinのmockライブラリで有名なMockK。便利ですよね。
MockitoのようにSpringに対応してくれればもっと便利なのになあと思っていたら、SpringMockKというそのものずばりなライブラリがあったので試してみました。

準備

Spring Initializrで作ったひな型に以下のようなサービスを追加します。
テストではこのサービスをmockにします。

HogeService.kt
package com.example.demo.service

import org.springframework.stereotype.Service

@Service
class HogeService {

    fun hoge() = "HogeService.hoge()"

    fun fuga() = "HogeService.fuga()"
}

また、HogeServiceを利用するコンポーネントも作成します。

Main.kt
package com.example.demo

import com.example.demo.service.HogeService
import org.springframework.stereotype.Component

@Component
class Main(
    private val hogeService: HogeService
) {

    fun main() = "${hogeService.hoge()}, ${hogeService.fuga()}"
}

build.gradleのdependenciesに以下を追加します。
com.ninja-squad:springmockkだけでなくnet.bytebuddy:byte-buddyも追加しないと動きませんでした。

build.gradle
dependencies {
    // ...略...
    // SpringMockK
    testImplementation 'net.bytebuddy:byte-buddy:1.9.12'
    testImplementation 'com.ninja-squad:springmockk:1.1.2'
    // ...略...
}

MockkBean

以下のようにmock化したいサービスに@MockkBeanアノテーションを付与するとよしなにmock化してくれます。
ちゃんとverifyもできますね。

SpringMockKTest.kt
package com.example.demo.service

import com.example.demo.Main
import com.ninjasquad.springmockk.MockkBean
import io.mockk.every
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
@SpringBootTest
class SpringMockKTest {

    @MockkBean
    private lateinit var hogeService: HogeService

    @Autowired
    private lateinit var main: Main

    @Test
    fun mainTest() {
        every { hogeService.hoge() } returns "SpringMockKHoge.hoge()"
        every { hogeService.fuga() } returns "SpringMockKHoge.fuga()"

        assertEquals("SpringMockKHoge.hoge(), SpringMockKHoge.fuga()", main.main())

        verify {
            hogeService.hoge()
            hogeService.fuga()
        }
    }
}

SpykBean

@SpykBeanアノテーションでspyもできます。

SpringMockKSpyTest.kt
package com.example.demo.service

import com.example.demo.Main
import com.ninjasquad.springmockk.MockkBean
import com.ninjasquad.springmockk.SpykBean
import io.mockk.every
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
@SpringBootTest
class SpringMockKSpyTest {

    @SpykBean
    private lateinit var hogeService: HogeService

    @Autowired
    private lateinit var main: Main

    @Test
    fun mainTest() {
        every { hogeService.hoge() } returns "SpringMockKHoge.hoge()"

        assertEquals("SpringMockKHoge.hoge(), HogeService.fuga()", main.main())

        verify {
            hogeService.hoge()
            hogeService.fuga()
        }
    }
}

おまけ

SpringMockKを利用せずにSpringでMockKを利用したい場合、以下の方法があるようです。
ただし、うまく動くのはバージョンが2.0.9.RELEASEまでで、Spring Initializrで生成したバージョン2.1.4.RELEASEではエラーで動きませんでした。

MockKTest.kt
package com.example.demo.service

import com.example.demo.Main
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.test.context.junit.jupiter.SpringExtension

// Springのバージョンが2.0.9.RELEASE までなら動く
@ExtendWith(SpringExtension::class)
@SpringBootTest
class MockKTest {

    @TestConfiguration
    class MockKConfig {

        @Bean
        fun hogeService() = mockk<HogeService>()
    }

    @Autowired
    private lateinit var hogeService: HogeService

    @Autowired
    private lateinit var main: Main

    @Test
    fun mainTest() {
        every { hogeService.hoge() } returns "MockKHoge.hoge()"
        every { hogeService.fuga() } returns "MockKHoge.fuga()"

        assertEquals("MockKHoge.hoge(), MockKHoge.fuga()", main.main())

        verify {
            hogeService.hoge()
            hogeService.fuga()
        }
    }
}

参考

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away