kosi-libs / MocKMP

A mocking processor for Kotlin Multiplatform
https://kosi-libs.org/mockmp
MIT License
183 stars 12 forks source link

Unable to run tests with mock on iOS #42

Closed kartik-prakash closed 1 year ago

kartik-prakash commented 1 year ago

I will shortly share a sample project on this, however when running tests for iOS in a multiplatform project, tests are passing for android but failing for iOS with the following error:

Uncaught Kotlin exception: org.kodein.mock.Mocker.MockingException: <My mocked class>.itsFunction() has not been mocked
Invalid connection: com.apple.coresymbolicationd

Anyone has seen that before or know how to resolve this?

SalomonBrys commented 1 year ago

How are you applying MocKMP ? Can you share a reproducer ?

kartik-prakash commented 1 year ago

@SalomonBrys Sorry for the delay, I was trying to figure out what's going on. So it seems like an issue with maybe scope in tests. Here is the setup:

interface Foo {
    fun doSomething(): Boolean
}

class Bar(private val foo: Foo) {
    suspend fun bar(): Boolean {
        return foo.doSomething()
    }
}

@UsesMocks(Foo::class)
class MyTest : TestsWithMocks() {
    override fun setUpMocks() {

    }

    private val myFoo: Foo = MockFoo(mocker)
    private val sut: Bar = Bar(myFoo)

    @BeforeTest
    fun setup() {
        println("setting up mock")
        every { myFoo.doSomething() } returns true
        println("done setting up mock")
    }

    @Test
    fun `this is a test`() = runTest {
        println("starting test")
        val actual = sut.bar()
        assertTrue { actual }
        println("finishing test")
    }
}

Output:

setting up mock
done setting up mock
starting test
Invalid connection: com.apple.coresymbolicationd

org.kodein.mock.Mocker.MockingException: MockFoo.doSomething() has not been mocked
org.kodein.mock.Mocker.MockingException: MockFoo.doSomething() has not been mocked
    at kotlin.Throwable#<init>(/opt/buildAgent/work/5f69639f351c4725/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:25)
    at kotlin.Exception#<init>(/opt/buildAgent/work/5f69639f351c4725/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23)
    at org.kodein.mock.Mocker.MockingException#<init>(/Users/runner/work/MocKMP/MocKMP/mockmp-runtime/src/commonMain/kotlin/org/kodein/mock/Mocker.kt:12)
    at org.kodein.mock.Mocker#register(/Users/runner/work/MocKMP/MocKMP/mockmp-runtime/src/commonMain/kotlin/org/kodein/mock/Mocker.kt:146)
    at org.kodein.mock.Mocker#register$default(/Users/runner/work/MocKMP/MocKMP/mockmp-runtime/src/commonMain/kotlin/org/kodein/mock/Mocker.kt:145)
    at com.physiq.monitor.mobile.data.provider.MockFoo#doSomething

The above test passes for android but fails for iOS. I'm assuming it's something to do with runTest{}. But explicitly calling setup() inside the test passes:

@Test
    fun `this is a test`() = runTest {
        val actual = sut.bar()
        assertTrue { actual }
    }
kartik-prakash commented 1 year ago

Update: Moving everything I have above in setup() to setupMocks() from TestsWithMocks solved the issue.

SalomonBrys commented 1 year ago

The problem came from:

    override fun setUpMocks() {

    }

You're supposed to override setUpMock with the injectMocks method that was generated:

override fun setUpMocks() = injectMocks(mocker)