Springboot配置Mockk构建更适合Kotlin后端的单测环境
引言
作为一个纯Kotlin后端的Springboot使用者,单测肯定是开发中必不可少的一部分,但是功能强大的主流框架Mockito由于是用于Java语言的,对于kotlin来说并不是很友好 而且一些关键字冲突比如when
,缺少函数式操作使得使用起来总感觉怪怪的,所以使用针对kotlin的mockk单测框架是个非常不错的选择。
添加依赖
mockk并没有提供spring生态的版本,大部分人都是用在安卓开发上。但是mockk提供了对于spring环境的使用建议,springmockk,并且附有spring官网的使用用例,虽然是第三方框架,但是spring官网的指南都是收录的所以不用过于担心。Spring Boot and Kotlin
如果实在想折腾不太信任第三方也可以自行去引用mockk官网的依赖去配置尝试接入到spring环境中
引入springmockk依赖
testImplementation("com.ninja-squad:springmockk:4.0.2")
移除springboot-test中包含的mockito避免依赖冲突
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude(module = "mockito-core")
}
编写单例测试
使用mockk可以当Mockito来用,提供了Mockito所有相关标准的api
//UserControllerTest.kt
@SpringBootTest
class UserControllerTest {
@Autowired
private lateinit var userInfoController: UserInfoController
@MockkBean
private lateinit var userInfoService: UserInfoService
@Test
fun `test api`() {
every { userInfoService.getUserInfo() } returns "hello1"
try {
assertThat(userInfoController.test()).isEqualTo("hello")
}catch (e: MockKException){
println("返回值不是预期的hello")
}
verify { userInfoService.getUserInfo() }
}
}
//UserInfoController.kt
@RestController
@CrossOrigin
@RequestMapping("user")
class UserInfoController(
private val service: UserInfoService,
) {
@GetMapping("test")
fun test() = service.getUserInfo()
}
//UserInfoService.kt
@Service
class UserInfoService {
fun getUserInfo() = "test"
fun getNewStr(str:String) = "test${str}"
}
版本兼容
mockk | springboot | jdk |
---|---|---|
4.x | 3.x | 17+ |
3.x | 2.4.x、2.5.x、2.6.x | 8+ |
2.x | 2.2.x、2.3.x | 8+ |
1.x | 2.1.x | 8+ |
JDK动态代理类无法获取问题
在github的说明中有提到在高版本jdk中,比如(Java 16+ AFAIK)中mockk无法对jdk代理的相关模块进行访问,会抛出错误比如
java.lang.IllegalAccessException: class io.mockk.impl.InternalPlatform cannot access a member of class java.lang.reflect.Proxy (in module java.base) with modifiers "protected"
请添加test任务中添加jvm参数用于允许访问动态代理的模块内容
//build.gradle.kts
tasks.withType<Test> {
jvmArgs(
"--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED"
)
}
转载自:https://juejin.cn/post/7382491990301753379