使用MockK和Kotlin的@SpringBootTest中出现UninitializedPropertyAccessException的原因是什么?

问题描述

我正在尝试将MockK 1.10.2与Kotlin 1.4.10和@SpringBoottest(Spring Boot 2.2.2.RELEASE)一起使用,由于出现问题,我无法使其运行

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot     loader classes because bootstrap classpath has been appended
2020-11-05 15:00:37.878  WARN   --- [           main] i.m.p.j.t.InliningClasstransformer       : Failed to transform class java/lang/Object

java.lang.IllegalArgumentException: Unsupported class file major version 59
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:195)
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:176)
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:162)
at net.bytebuddy.utility.OpenedClassReader.of(OpenedClassReader.java:86)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:3394)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1933)
at net.bytebuddy.dynamic.scaffold.inline.RedeFinitionDynamicTypeBuilder.make(RedeFinitionDynamicTypeBuilder.java:217)
at net.bytebuddy.dynamic.scaffold.inline.AbstractInliningDynamicTypeBuilder.make(AbstractInliningDynamicTypeBuilder.java:120)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3404)
at io.mockk.proxy.jvm.transformation.InliningClasstransformer.transform(InliningClasstransformer.kt:77)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
at io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation.retransform(JvmInlineInstrumentation.kt:28)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:19)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:6)
at io.mockk.proxy.common.transformation.ClasstransformationSpecMap.applyTransformation(ClasstransformationSpecMap.kt:41)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation.execute(RetransformInlineInstrumnetation.kt:16)
at io.mockk.proxy.jvm.ProxyMaker.inline(ProxyMaker.kt:88)
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:30)

kotlin.UninitializedPropertyAccessException: lateinit property taService has not been initialized

例外。 (如果我使用tmpService,也会发生同样的情况。导入的服务与测试类位于相同或不同的包中都没有关系。)

从测试类的代码中可以看到,我已经玩了很多次,但到目前为止还没有成功。

package com.xxx.emr.tm

import com.xxx.data.emr.model.PatientAssignment
import com.xxx.data.tm.TMPService
import com.xxx.data.tm.model.MyType
import com.xxx.data.tm.model.MyTypeCode
import com.xxx.data.tm.model.UserAction
import com.xxx.emr.service.model.AuthenticatedUser
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.SpyK
import io.mockk.junit5.MockKExtension
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.verify
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBoottest

 @ExtendWith(SpringExtension::class,MockKExtension::class)
 @SpringBoottest // (classes = [com.xxx.emr.service.MyServiceSpringBoot::class])
// @RunWith(SpringJUnit4ClassRunner::class)    
// @ActiveProfiles("test")
// @EnableAutoConfiguration
// @AutoConfiguremockmvc
class MyTest {
// (
//    val tmpService: TMPService,//    val taService: TaService
// )

//    @InjectMockKs
//    @Autowired
//    @SpyK
@MockK
private lateinit var tmpService: TMPService

@InjectMockKs
@Autowired
private lateinit var taService: TaService

@Test
fun assignAToB() {
    
    MockKAnnotations.init(this,relaxUnitFun = true)

    val vId = "xxx"
    val authUser: AuthenticatedUser = AuthenticatedUser.mockedUser()
    val userAction = UserAction(
        userId = "user_id",actionCode = ActionType.GET_IT,sessionId = "sessionId"
    )

    val xxx = MyType(
        MyTypeCode.ABC.value,MyTypeCode.ABC.name,)

    val actionResult = UserActionResult(hashMapOf("success" to true))

//        every { tmpService.getXxx(any()) } returns xxx

    verify( exactly = 1 ) {
        tmpService.doSomething(any(),any(),any())
    }

    verify( exactly = 1 ) {
         taService.dowhatYouWant(„vId",authUser,userAction)
    }
}

自动布线不起作用...那是我的错?我怎样才能完全执行测试?

解决方法

我认为您应该首先通过将其添加到测试文件中来初始化模拟,例如:

@org.springframework.test.context.event.annotation.BeforeTestMethod
fun initMocks() {
    org.mockito.MockitoAnnotations.initMocks(this)
}

我在另一个线程上发表了一篇有关如何设置单元测试的帖子,与您的要求相当: https://stackoverflow.com/a/64669499/7919904