17

I'm working on a Kotlin-multiplatform (KMP) library for iOS / Android. I have written some unit tests for JVM, for which I use MockK to create spies and mocks, but MockK doesn't support Kotlin native fully yet.

Therefore, I was wondering how others working on KMP projects write unit tests for the iOS platform. An example would be really appreciated.

5 Answers 5

8

Currently, MockK does not support Kotlin/Native or Kotlin/JS. However, both are placed as important items on the project backlog:

This is a big challenge given that a mocking library relies heavily on language features such as reflection which are not fully supported yet on Kotlin multiplatform (and possibly even can't be supported without considerable workarounds for specific platforms).

This does not prevent you from writing custom mock classes and verify states you set therein, of course, of which the tests will be able to run on all platforms.

Sign up to request clarification or add additional context in comments.

Comments

5

You can use Mockative to mock interfaces in Kotlin/Native and Kotlin Multiplatform, not unlike how you'd mock dependencies using MockK or Mockito.

Full disclosure: I am one of the authors of Mockative

Here's an example:

class GitHubServiceTests {
    @Mock val api = mock(classOf<GitHubAPI>())

    val service = GitHubService(api)

    @Test
    fun test() {
        // Given
        val id = "mockative/mockative"
        val mockative = Repository(id = id, name = "Mockative")
        given(api).invocation { fetchRepository(id) }
            .thenReturn(mockative)

        // When
        val repository = service.getRepository(id)

        // Then
        assertEquals(mockative, repository)

        // You can also verify function calls on mocks
        verify(api).invocation { fetchRepository(id) }
            .wasInvoked(exactly = once)
    }
}

Spies aren't currently supported, but they are on the roadmap.

Comments

4

I looked around and asked in Kotlin' General slack which by the way is a great space where you can ask directly the Kotlin devs and the enthusiasts Kotlin language related questions including multi-platform stuff.

But as for the time I'm writing this, I Don't think you can mock for the common module with Mockk or any other mocking library.

What you can for tests in the common module which is targeted to native as one of the platforms is the old-fashioned interface/impl/stub approach.

Comments

1

I test the common sources in androidTest. There Mockk is available.

I think it is sufficient because Android uses exactly the same code as the common module.

shared
> src
>> androidMain 
>> androidTest < tests here
>> commonMain < code here

2 Comments

aren't tests supposed to go on androidTest?
One downside with this approach is that in the androidTest, you will not have any issues with the kotlin/native memory model; mutating frozen data, transferring state over threads etc etc. You will only encounter these issues when testing your code in your iOS codebase like this.
1

One library similar to Mockative I found that provides a nice API for mocking interfaces and fakes for data classes in common tests is MocKMP from the folks at Kodein. A simple usage from the docs can be found below:

class MyTest : TestsWithMocks() {
    override fun setUpMocks() = injectMocks(mocker) //(1)

    @Mock lateinit var view: View
    @Fake lateinit var model: Model

    val controller by withMocks { Controller(view = view, firstModel = model) }

    @Test fun controllerTest() {
        every { view.render(isAny()) } returns true
        controller.start()
        verify { view.render(model) }
    }
}

Here is an article explaining how to use it as well. The only caveat to this approach is you need to generate the symbols first before you have access to injectMocks(mocker) method since the library uses kotlin symbol processing to generate the this method which provides the mocks.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.