首页 > 解决方案 > 当方法的默认参数需要注入字段时如何模拟?

问题描述

我的类有一个带有默认参数的方法,其值是从注入的参数派生的:

class Slack @Inject constructor(
  private val brokerSettings: BrokerSettings
) {

  fun alert(
    message: String,
    responsible: String = brokerSettings.slack?.responsible ?: "<!here>",
    channels: List<String>? = brokerSettings.slack?.channels
  ) {
   ...
  }
}

我可以构造一个mockk<Slack>,但是当我的测试尝试调用alert(message)它时,依赖于默认参数,我在alert$default.

如果我将brokerSettings.slack上面更改为brokerSettings?.slack,那么它可以工作 - 但警告我我不需要额外的?.

我试着嘲笑这个brokerSettings领域的吸气剂:

val slack = mockk<Slack>(relaxed = true)
{
//    every { this@mockk.brokerSettings } answers { BrokerSettings() }
//    every { this getProperty "brokerSettings" } propertyType BrokerSettings::class answers { BrokerSettings() }
}

this@mockk.brokerSettings如果该字段是私有的,则无法编译,并且如果它是公共的,则会像原始问题一样抛出 NPE,并且会this getProperty因反射错误而失败。

我现在通过将默认值设置为null并使用?:来有条件地计算函数内部的默认值,但我不想这样做。

有任何想法吗?

标签: kotlinnullpointerexceptionmockingmockkdefault-parameters

解决方案


这是我的第一个答案的编辑/完整重写。我显然对真正的问题关注得太少了。

你需要做的是:

  • BrokerSettings为实例创建一个模拟
  • 将模拟配置为不会在slackgetter上失败
  • 创建一个传入模拟的真实 Slack实例
  • Slack用间谍包装该实例
  • 将该间谍配置为不在alert函数中执行任何实际操作
  • 把间谍放到你的班级接受测试
  • 调用你要测试的方法
  • 验证slack.alert通话

在科特林:

class SlackUsingClass(private val slack: Slack) {
    fun doIt(message: String) {
        slack.alert(message)
    }
}
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import org.junit.jupiter.api.Test

class SlackUsingClassTest {

    @Test
    fun `should call slack`() {

        val brokerSettings = mockk<BrokerSettings>()
        every { brokerSettings.slack } returns null

        val slack = spyk(Slack(brokerSettings))
        every { slack.alert(any(), any(), any())} just Runs

        val slackUsingClass = SlackUsingClass(slack)

        slackUsingClass.doIt("test")

        verify { slack.alert("test", any(), any()) }

    }
}

推荐阅读