Как вы Mockk функции верхнего уровня Kotlin?

Mockk позволяет высмеивать статические функции, но как можно высмеивать функцию верхнего уровня Kotlin?

Например, если у меня есть файл Kotlin с именем HelloWorld.ktкак мне издеваться sayHello() функционировать?


HelloWorld.kt

fun sayHello() = "Hello Kotlin!"

7 ответов

Решение

Есть способ макетировать функцию верхнего уровня:

mockkStatic("pkg.FileKt")
every { fun() } returns 5

Вам просто нужно знать, какой файл эта функция идет. Проверьте в JAR или трассировку стека.

Мне подошел следующий синтаксис.

mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)

Я удивлен, что на jvm-stdlib пока для этого.

Чтобы добавить предыдущие ответы, это работает:

mockkStatic("pkg.FileKt")
every { fun() } returns 5

Где mockStatic принимает в качестве аргумента "package_name:class_file_name" Но для упрощения вызова mockStatick вы можете дать своему файлу имя для компилятора с помощью @file:JvmName прямо в файле.

HelloWorld.kt

@file:JvmName("hello")
fun sayHello() = "Hello Kotlin!"

HelloWorldTest.kt

mockkStatic("pkg.hello")
every { fun() } returns 5

Более подробное объяснение того, почему это необходимо, и другие примеры здесь:https://blog.kotlin-academy.com/mocking-is-not-rocket-science-mockk-advanced-features-42277e5983b5

Этот код не работает для меня с mockk версии 1.10.0, но хорошо работает в 1.11.0 (конечно, нужно изменить mockkStatic(::bar))

Utils.kt

      @file:JvmName("UtilsKt")
package com.example.myapplication

fun foo(): Boolean {
  return bar()
}

fun bar():Boolean {
  return false
}

Контрольная работа

      @RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1])
class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        mockkStatic("com.example.myapplication.UtilsKt")
        every { bar() } returns true
        assertTrue(foo())
    }
}

@oleksiyp ответ работает. Вот пример:

HelloWorld.kt

package hello

fun sayHello() = "Hello Kotlin!"

Tests.kt

package hello

import io.mockk.every
import io.mockk.mockkStatic
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test

class Tests {
    @Test
    fun `Top level mocking`() {
        mockkStatic("hello.HelloWorldKt")
        every { sayHello() } returns "Hello Mockk"

        val actual = sayHello()
        Assertions.assertEquals(actual, "Hello Mockk")
    }
}

К сожалению, кажется, что мой оригинальный вопрос был слишком прост, потому что это не решает мою реальную проблему мира

Опираясь на ответ Сергея:

Вы могли бы иметь фактическую реализацию sayHello() функция в переменной, то это значение по умолчанию параметра функции для sayHello(),

Этот пример работает:

package tests

import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test

val sayHelloKotlin = { "Hello Kotlin!" }
fun sayHello(producer: () -> String = sayHelloKotlin): String = producer()

class Tests {
    interface Producer {
        fun produce(): String
    }

    @Test
    fun `Top level mocking`() {
        val mock = mockk<Producer>()
        every { mock.produce() } returns "Hello Mockk"

        val actual = sayHello(mock::produce)
        Assertions.assertEquals(actual, "Hello Mockk")
    }
}

Проблема в том, что вы изменяете производственный код, чтобы обслуживать тестирование, и это кажется надуманным.

Способ Гмаззо:

      mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)

работал у меня хорошо.

Только не забудьте:

unmockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin) в конце

Другие вопросы по тегам