mockk,如何为 MutableMap<String, String> 使用插槽

mockk, how to use slot for MutableMap<String, String>

使用 mockk 1.9.3

有待验证的功能

class EventLogger 私有构造函数()

fun logUserEvent(eventName: String?, eventParamMap: MutableMap<String, String>?) {
   ......
    internaLogEventImpl(eventName, eventParamMap)
}

internal fun internaLogEventImpl(eventName: String?, customParams: MutableMap?) { …… }

companion object {
     @Volatile
     private var sEventLoggerSingleton: EventLogger? = null

     @JvmStatic
    val instance: EventLogger
        get() {
            if (sEventLoggerSingleton == null) {
                sEventLoggerSingleton = EventLogger()
            }
            return sEventLoggerSingleton!!
        }
}

在每个 {eventLogger.internaLogEventImpl(any(), mapSlot)} 出现编译器错误

类型不匹配。 必需:MutableMap? 找到:CapturingSlot> 在下面尝试时:

class 测试K {

lateinit var eventLogger: EventLogger
lateinit var application: Application

val mapSlot = slot<MutableMap<String, String>>()

@Before
fun setUp() {
    application = ApplicationProvider.getApplicationContext<Application>()
    eventLogger = mockk.spyk(EventLogger.instance)
    ReflectionHelpers.setStaticField(EventLogger::class.java, "sEventLoggerSingleton", eventLogger)
}

@After
fun cleanUp() {
    ReflectionHelpers.setStaticField(EventLogger::class.java, "sEventLoggerSingleton", null)
}

@Test
fun logNotificationStatusChange_with_enabled_WhenCalled_ShouldLog() {

    val testMap = hashMapOf("action" to "open")

    every {eventLogger.internaLogEventImpl(any(), mapSlot)} answers {
        println(mapSlot.captured)
        assert(mapSlot.captured["action"] == "open")
    }
    eventLogger.logUserEvent("test_event", testMap)
}

}

您需要使用 capture(参见 Mockk's Capturing section)。

所以对于你的情况 capture(mapSlot) 应该有效。

eventLogger.internaLogEventImpl(any(), capture(mapSlot))

在尝试模拟复杂代码之前,最好学习更简单的示例。

这是一个使用 mockk 在 object 上模拟私人通话的工作示例。

object MyLogger {
    fun logUserEvent(event: String?, map: MutableMap<String, String>?) {
        // turns the event string into an uppercase string.
        internaLogEventImpl(event?.toUpperCase(), map)
    }

    private fun internaLogEventImpl(event: String?, map: MutableMap<String, String>?): Unit =
        throw Exception("real implementation")
}

如何测试和模拟内部函数,这样我们就不会抛出异常。

@Test
fun `test logger internal`() {
    val expectedMap = mutableMapOf("a" to "b")
    val expectedEvent = "EVENT"

    val mock = spyk(MyLogger, recordPrivateCalls = true)
    justRun { mock["internaLogEventImpl"](expectedEvent, expectedMap) }
    // or justRun { mock["internaLogEventImpl"](any<String>(), any<MutableMap<String, String>>()) }

    mock.logUserEvent("event", expectedMap)

    verify { mock["internaLogEventImpl"](expectedEvent, expectedMap) }
}

此处logUserEvent调用真实实现,internaLogEventImpl调用模拟实现。

如果justRun { mock["internaLogEventImpl"](expectedEvent, expectedMap) }没有被调用(或者由于参数不匹配而错误),真正的实现将被调用。在这里它会抛出 Exception("real implementation").

请尝试修改值以检查不同的行为。