繁体   English   中英

Mockk 在 Kotlin 中设置集合的私有属性

[英]Mockk set private properties of collection in Kotlin

在 Mockk 中访问私有变量时,无法设置私有属性的值。

我们有 CustomerImpl class,它有 1 个名为customerData的私有属性。

我们希望在不调用updateCache()方法的情况下从我们的测试用例中设置私有属性customerData中的数据。

我们正在使用Mockk 1.10.6

CustomerImpl Class

class CustomerImpl {
    private var customerData : MutableList<CustomerModel> = mutableListOf()

    private fun updateCache() {
        ... here customerData is updated.
    }

    fun clearCache() {
        if(customerData.isNotEmpty())
            customerData.clear()
    }
}

测试 Class

class CustomerImplTest {

    private lateinit var customerImpl: CustomerImpl

    @Before
    fun setUp() {

        MockKAnnotations.init(this)

        customerImpl = spyk(CustomerImpl(), recordPrivateCalls = true)
    }

    @Test
    fun clearCacheTest() {
        val customer = listOf(CustomerModel(id = "3", name = "John"))
        every { customerImpl setProperty "customer" value customer } just Runs

        customerImpl.clearCache()
    }
}

当我们尝试运行这个测试用例时,它给了我们以下错误。

例外

io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock

    at io.mockk.impl.recording.states.StubbingState.checkMissingCalls(StubbingState.kt:14)
    at io.mockk.impl.recording.states.StubbingState.recordingDone(StubbingState.kt:8)
    at io.mockk.impl.recording.CommonCallRecorder.done(CommonCallRecorder.kt:47)
    at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:60)
    at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    at io.mockk.MockKDsl.internalEvery(API.kt:92)
    at io.mockk.MockKKt.every(MockK.kt:98)
    at com.xyz.impl.CustomerImplTest.clearCacheTest(CustomerImplTest.kt:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

我们只在 Mockk 中寻找解决方案。

如果您希望能够使用您的 class 测试所有场景,您应该注入所有依赖项而不是在内部创建对象。

正如已经建议的那样,您需要将列表作为构造函数参数传递。

class CustomerImpl(
    private var customerData : MutableList<CustomerModel> = mutableListOf()
) {    
    private fun updateCache() {
        // Here customerData is updated.
    }

    fun clearCache() {
        if(customerData.isNotEmpty())
            customerData.clear()
    }
}

class 的真正消费者将以相同的方式工作,但您将能够注入依赖项。 如果您担心以某种方式暴露customerData数据,请考虑您可以/应该有一种工厂来构建实例而不知道具体的 class。例如:

interface Customer {
    fun clearCache()

    companion object {
        fun newInstance(): Customer = CustomerImpl()
    }
}

class CustomerImpl(
    private var customerData : List<CustomerModel> = mutableListOf()
): Customer {    
    private fun updateCache() {
        // Here customerData is updated.
    }

    override fun clearCache() {
        if(customerData.isNotEmpty())
            (customerData as? MutableList)?.clear()
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM