はじめに
SpringBootTestでControllerの単体テストを記述する際にService層のクラスの一部の関数をMock化する例です。
Mockkの解説ページにBeanのMock化手法が載っていなかったのでやり方を調べてみました。
バージョン等
SpringFrameWork
: 2.2.6
Mockk
:1.11.0
ソースコード例
@Service
class Service(
something: Something
) {
fun notTargetServiceFunction() : String {
return "Not target!"
}
fun targetServiceFunction() : String {
return "Not mock!"
}
}
Service層のクラスは@Service
アノテーションによりBean化され、DIコンテナに登録されます。
@RestController
class Controller (
val service: Service
) {
@GetMapping("/path")
fun targetControllerFunction(): ResponseEntity<String> {
service.targetServiceFunction().let {
notTargetServiceFunction()
return ResponseEntity.ok(it)
}
}
}
Controllerも@RestController
アノテーションによりBean化されています。
(省略記法によりserviceの依存性注入も行っている)
class ApplicationTests {
@Autowired
private lateinit var webApplicationContext: WebApplicationContext
lateinit var controllerMockMvc: MockMvc
@SpykBean
private lateinit var service: Service
@BeforeEach
fun initController() {
controllerMockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build()
}
@Test
fun test() {
every {
cdcUserService.targetServiceFunction()
} returns "Mock!"
val expectedResponse = "Mock!"
controllerMockMvc.perform(MockMvcRequestBuilders.get(PATH))
.andExpect(content().string(expectedResponse))
}
}
Mockkを使用してBean化されシングルトンとして存在するServiceのインスタンスをMock化するには@MockkBean
or@SpykBean
を使用します。
every文のところでMock関数の定義を行っています。
@MockkBean
と@SpykBean
の違いは全ての関数がMock化されるか、一部の関数だけMock化するかの違いです。
@MockkBean
ではevery文で定義しなかった関数は何も返さない関数に置き換わりますが、
@SpykBean
ではevery文で定義しなかった関数はそのままオリジナルの関数の定義を引き継ぎます。