kotlinのmockライブラリで有名なMockK。便利ですよね。
MockitoのようにSpringに対応してくれればもっと便利なのになあと思っていたら、SpringMockKというそのものずばりなライブラリがあったので試してみました。
準備
Spring Initializrで作ったひな型に以下のようなサービスを追加します。
テストではこのサービスをmockにします。
package com.example.demo.service
import org.springframework.stereotype.Service
@Service
class HogeService {
fun hoge() = "HogeService.hoge()"
fun fuga() = "HogeService.fuga()"
}
また、HogeServiceを利用するコンポーネントも作成します。
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
も追加しないと動きませんでした。
dependencies {
// ...略...
// SpringMockK
testImplementation 'net.bytebuddy:byte-buddy:1.9.12'
testImplementation 'com.ninja-squad:springmockk:1.1.2'
// ...略...
}
MockkBean
以下のようにmock化したいサービスに@MockkBean
アノテーションを付与するとよしなにmock化してくれます。
ちゃんとverifyもできますね。
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もできます。
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ではエラーで動きませんでした。
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()
}
}
}