Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Kotlin multiplatform project fails to build with mockk dependency #322

Open
2 of 3 tasks
littleGnAl opened this issue Jun 23, 2019 · 29 comments
Open
2 of 3 tasks

Comments

@littleGnAl
Copy link

littleGnAl commented Jun 23, 2019

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

Current Behavior

I'm working on a kotlin multiplatform project, when I try to write some unit test by using MockK, I got the Unresolved reference: xxx error when I run the ./gradlew :common:build, don't actually know this case relates to this issue(#58 ) or not.

...

> Task :common:linkTestDebugExecutableIos FAILED
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (3, 8): Unresolved reference: io
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (4, 8): Unresolved reference: io
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (5, 8): Unresolved reference: io
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (11, 4): Unresolved reference: MockK
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (18, 5): Unresolved reference: MockKAnnotations
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (26, 5): Unresolved reference: verify
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (40, 5): Unresolved reference: verify
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (52, 5): Unresolved reference: verify
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (59, 5): Unresolved reference: verify
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (66, 5): Unresolved reference: verify
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (73, 5): Unresolved reference: verify
e: xxx/accounting-multiplatform/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt: (80, 5): Unresolved reference: verify
8 actionable tasks: 8 executed
19:05:52: Task execution finished 'build'.


Steps to Reproduce

You can clone the project https://github.com/littleGnAl/accounting-multiplatform/tree/littlegnal/common-test.

Uncomment the https://github.com/littleGnAl/accounting-multiplatform/blob/littlegnal/common-test/android/common/src/commonTest/kotlin/com/littlegnal/accountingmultiplatform/data/SqlDelightManagerTest.kt.

Then run the ./gradlew :common:build to reproduce

Context

My gradle configuration is like below:

apply plugin: 'org.jetbrains.kotlin.multiplatform'
apply plugin: 'com.squareup.sqldelight'
apply plugin: 'kotlinx-serialization'

sqldelight {
    AccountingDB {
        packageName = "com.littlegnal.accountingmultiplatform"
    }
}

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation deps.kotlin.stdlib.stdlib
                implementation deps.kotlin.serialiaztion.runtime.common
                implementation deps.kotlin.coroutines.common
            }
        }

        commonTest {
            dependencies {
                implementation deps.kotlin.coroutines.core
                implementation deps.kotlin.coroutines.common
                implementation deps.kotlin.coroutines.test
                implementation deps.kotlin.test.common
                implementation deps.kotlin.test.annotations
//                implementation deps.mockk.common
//                implementation deps.mockk.mockk
                implementation "io.mockk:mockk-common:1.9.3"
                implementation "io.mockk:mockk:1.9.3"

            }
        }

        androidTest {
            dependencies {
                implementation deps.kotlin.test.test
                implementation deps.kotlin.test.junit
            }
        }

        androidMain {
            dependencies {
                implementation deps.kotlin.stdlib.stdlib
                implementation deps.sqldelight.runtimejvm
                implementation deps.kotlin.serialiaztion.runtime.runtime
                implementation deps.kotlin.coroutines.android
            }
        }

        iosMain {
            dependencies {
                implementation deps.kotlin.stdlib.stdlib
                implementation deps.sqldelight.driver.ios
                implementation deps.kotlin.serialiaztion.runtime.native
                implementation deps.kotlin.coroutines.native
            }
        }

        iosTest {
            dependencies {
                implementation "io.mockk:mockk-common:1.9.3"
                implementation "io.mockk:mockk:1.9.3"
            }
        }
    }

    targets {
        fromPreset(presets.jvm, 'android')
        final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
                              ? presets.iosArm64 : presets.iosX64

        fromPreset(iOSTarget, 'ios') {
            binaries {
                framework('common')
            }
        }
    }
}

// workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations {
    compileClasspath
}

task packForXCode(type: Sync) {
    final File frameworkDir = new File(buildDir, "xcode-frameworks")
    final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
    final def framework = kotlin.targets.ios.binaries.getFramework("common", mode)

    inputs.property "mode", mode
    dependsOn framework.linkTask

    from { framework.outputFile.parentFile }
    into frameworkDir

    doLast {
        new File(frameworkDir, 'gradlew').with {
            text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
            setExecutable(true)
        }
    }
}

task iosTest {
    def device = project.findProperty("iosDevice")?.toString() ?: "iPhone 8"
    dependsOn 'linkTestDebugExecutableIos'
    group = JavaBasePlugin.VERIFICATION_GROUP
    description = "Runs tests for target 'ios' on an iOS simulator"

    doLast {
        def binary = kotlin.targets.ios.compilations.test.getBinary('EXECUTABLE', 'DEBUG')
        exec {
            commandLine 'xcrun', 'simctl', 'spawn', device, binary.absolutePath
        }
    }
}

tasks.build.dependsOn packForXCode
  • MockK version: 1.9.3
  • OS: macOS Mojave 10.14.4
  • Kotlin version: 1.3.31
  • Type of test: unit test OR android instrumented test: Unit test
@oleksiyp
Copy link
Collaborator

Thanks for the report

@AdibaM
Copy link

AdibaM commented Jul 31, 2019

Did you find a work around for this?

@Bradleycorn
Copy link

same issue here ... any way to work around this?

@desgraci
Copy link

desgraci commented Oct 1, 2019

Same issue Kotlin version: 1.3.50

@oleksiyp oleksiyp added the bug label Nov 1, 2019
@oleksiyp oleksiyp added this to the 1.9.4 milestone Nov 1, 2019
@oleksiyp oleksiyp changed the title Unresolved reference when run the task linkTestDebugExecutableIos in kotlin multiplatform project Bug: Kotlin multiplatform project fails to build with mockk dependency Nov 1, 2019
@oleksiyp oleksiyp added this to To do in Critical to fix Nov 2, 2019
@heinhtetaung92
Copy link

Hello. Same here. Any update on this?

@danielocampo2
Copy link

Had the same issue. For now I had to stop using mockk altogether for KMP as I don't know any workaround.

Is there any update?

Thanks!

@xiaobailong24
Copy link

Same issue with Kotlin multiplatform-1.4.0. Except new update to fix it.

@jcfuerte
Copy link

Same Issue, someone has an update for this?

Thanks!

@Ornolfr
Copy link

Ornolfr commented Oct 21, 2020

Any workaround available?

@danielocampo2
Copy link

I think basically mockk has no support for Kotlin Multiplatform so it is not possible to use this library with it.

@jcfuerte
Copy link

I think basically mockk has no support for Kotlin Multiplatform so it is not possible to use this library with it.

probably soon it could be supported

@Dallanosm
Copy link

Same issue here :(

@scottnj
Copy link

scottnj commented Dec 7, 2020

I just started playing with Kotlin Multiplatform recently so I am not too familiar with it yet, but today I tried adding MockK to one of my commonTest tests and it seems to be working.

I'm using
Windows 10
IntelliJ IDEA 2020.3 (Ultimate Edition)
Kotlin 1.4.21
MockK: I tried both 1.10.3 and 1.10.3-jdk8

val atomicfuVersion = "0.14.4"
val mockkVersion = "1.10.3-jdk8"

plugins {
    kotlin("multiplatform") version "1.4.21"
}

group = "com.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

kotlin {
    explicitApi()
    jvm {
        compilations.all {
            kotlinOptions.jvmTarget = "1.8"
        }
        testRuns["test"].executionTask.configure {
            useJUnitPlatform()
        }
    }
    js(LEGACY) {
        browser {
            testTask {
                useKarma {
                    useChromeHeadless()
                }
            }
        }
    }
    val hostOs = System.getProperty("os.name")
    val isMingwX64 = hostOs.startsWith("Windows")
    val nativeTarget = when {
        hostOs == "Mac OS X" -> macosX64("native")
        hostOs == "Linux" -> linuxX64("native")
        isMingwX64 -> mingwX64("native")
        else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
    }

    
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlinx:atomicfu:$atomicfuVersion")
            }
        }
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test-common"))
                implementation(kotlin("test-annotations-common"))
                implementation("io.mockk:mockk-common:$mockkVersion")
                implementation("io.mockk:mockk:$mockkVersion")
            }
        }
        val jvmMain by getting
        val jvmTest by getting {
            dependencies {
                implementation(kotlin("test-junit5"))
                implementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
                runtimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
            }
        }
        val jsMain by getting
        val jsTest by getting {
            dependencies {
                implementation(kotlin("test-js"))
            }
        }
        val nativeMain by getting
        val nativeTest by getting
    }
}

Here is my test file under commonTest

import io.mockk.*
import io.mockk.impl.annotations.MockK
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals

interface Car {
    fun drive(direction: Direction) : Outcome
}

enum class Direction { NORTH, SOUTH }

enum class Outcome { GOING_NORTH, GOING_SOUTH }

class CarTest {

    @MockK
    private lateinit var annotatedCar: Car

    @BeforeTest
    fun setUp() {
        MockKAnnotations.init(this)
    }

    @AfterTest
    fun tearDown() {
        unmockkAll()
    }

    @Test
    fun mockkCar() {
        val mockkCar = mockk<Car>()
        every { mockkCar.drive(Direction.NORTH) } returns Outcome.GOING_NORTH
        every { mockkCar.drive(Direction.SOUTH) } returns Outcome.GOING_SOUTH

        assertEquals(Outcome.GOING_SOUTH, mockkCar.drive(Direction.SOUTH))
        assertEquals(Outcome.GOING_NORTH, mockkCar.drive(Direction.NORTH))

        verify { mockkCar.drive(Direction.NORTH) }
        verify { mockkCar.drive(Direction.SOUTH) }

        confirmVerified(mockkCar)
    }

    @Test
    fun annotatedCar() {
        every { annotatedCar.drive(Direction.NORTH) } returns Outcome.GOING_NORTH
        every { annotatedCar.drive(Direction.SOUTH) } returns Outcome.GOING_SOUTH

        assertEquals(Outcome.GOING_SOUTH, annotatedCar.drive(Direction.SOUTH))
        assertEquals(Outcome.GOING_NORTH, annotatedCar.drive(Direction.NORTH))

        verify { annotatedCar.drive(Direction.NORTH) }
        verify { annotatedCar.drive(Direction.SOUTH) }

        confirmVerified(annotatedCar)
    }
}

@gacordeiro-luizalabs
Copy link

One thing I noticed is the default gradle tasks executed when I select a test on my commonTest module and run are cleanIosX64Test and iosX64Test.

I am not sure why those are the defaults for this module, but if I instead run testDebugUnitTest or testReleaseUnitTest, then my commonTest tests run properly... but I still don't have any tests on my iosTest, so I don't know how this would behave

@sergey-morenets
Copy link

Reproduces in Kotlin 1.4.32

@ILikeYourHat
Copy link

Probably found the workaround. Instead of just adding:
implementation("io.mockk:mockk-common:$mockkVersion")
add also:
implementation("io.mockk:mockk:$mockkVersion")

Works like a charm for my project

@rocketraman
Copy link

@ILikeYourHat Thank you, that worked for me too.

@rocketraman
Copy link

Unfortunately the solution of adding implementation("io.mockk:mockk:$mockkVersion") breaks the gradle project sync, see #513.

@YKakdas
Copy link

YKakdas commented Apr 19, 2021

I do not know how but after appliying this, now my files see mockk dependency and kmm project structure also not broken:

   val commonTest by getting {
        dependencies {
            implementation(kotlin("test-common"))
            implementation(kotlin("test-annotations-common"))
            implementation("io.mockk:mockk-common:1.11.0")
        }
    }

    val androidTest by getting {
        dependencies {
            implementation(kotlin("test"))
            implementation(kotlin("test-junit"))
            implementation("junit:junit:4.13.2")
            implementation("io.mockk:mockk:1.11.0")

        }
    }

@TomWayne98
Copy link

Same issue here. When using Mock we can run the test in commonTest but when trying to run the test in iosTest folder it fails on :compileTestKotlinIosX64 task

@leocabral
Copy link

there's an effective and easy workaround for this issue if your goal is to use mockk in commonTest and run your tests using jvm.

if that's your case, here's my tip: create stub implementations of io.mockk inside iosTest directory.

if you want to use verify in your commonTest, just create a file, e.g: Mockk.kt, within the correct package structure (io.mockk) and create your stubbed verify:

fun verify(
    ordering: Ordering = Ordering.UNORDERED,
    inverse: Boolean = false,
    atLeast: Int = 1,
    atMost: Int = Int.MAX_VALUE,
    exactly: Int = -1,
    timeout: Long = 0,
    verifyBlock: MockKVerificationScope.() -> Unit
) = {
    TODO()
}

another tip to make your life easier is to open mockk method implementation using your IDE and just copy the signature and paste on your stubbed mockk 😄

attention that you only have to create these stubs inside iosTest source set.

disclaimer: I'm not providing an elegant way or the best solution ever. For now, it's the easiest way that I found to solve my problems. 🍻

@silverhammermba
Copy link

silverhammermba commented Sep 10, 2021

It looks like all of the "solutions" here are workarounds to get the tests building and running on something other than the native Apple-compatible code. That part we have working no problem. No one seems to be able to get mockk tests running natively on a Mac.

@leocabral
Copy link

It looks like all of the "solutions" here are workarounds to get the tests building and running on a non-Mac machine. That part we have working no problem. No one seems to be able to get mockk tests running natively on a Mac.

yes, you are right about the workarounds and stuff! actually the solution I've mentioned above works on mac machines 😃

@silverhammermba
Copy link

silverhammermba commented Sep 10, 2021

@leocabral but aren't you running the tests using the JVM, which is not how the code would execute on an iOS simulator or a real iOS device?

I want to verify the functionality of the code when compiled for iOS itself (or least simulator), not the JVM.

@leocabral
Copy link

@silverhammermba yes, I am! so indeed, your need cannot be accomplished by mockk.

@ComBatVision
Copy link

ComBatVision commented Sep 23, 2022

Hi. Any news about this issue? I can not publish my KMP library due to this issue during JS test task.

Unresolved reference: mockk
Unresolved reference: mockkStatic
Unresolved reference: every
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:

@pedrofraca
Copy link

Hi @ComBatVision , you can just change the name of your directory from commonTest to jvmTest, as well as your gradle section to something like this:

val jvmTest by getting { dependencies { implementation(kotlin("test-junit")) implementation("io.mockk:mockk:1.9.3") } }

@mecoFarid
Copy link

I think basically mockk has no support for Kotlin Multiplatform so it is not possible to use this library with it.

probably soon it could be supported

Almost 3 years, how soon? LOL

@mecoFarid
Copy link

Unfortunately the solution of adding implementation("io.mockk:mockk:$mockkVersion") breaks the gradle project sync, see #513.

See @YKakdas's answer. It works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests