streetcomplete / StreetComplete

Easy to use OpenStreetMap editor for Android
https://streetcomplete.app
GNU General Public License v3.0
3.64k stars 336 forks source link

Use multiplatform mocking library for tests #5420

Open westnordost opened 5 months ago

westnordost commented 5 months ago

For mocking unit tests, we are currently using the Java library org.mockito:mockito.

In order that the tests for platform-independent application logic can be executed on any supported platform, mockito needs to be replaced as a test dependency.

Mocking library requirements

It is possible that when migrating, a bit more effort is necessary because as far as I know, Mockito uses Java reflection to create the mocks, which is a Java specific language feature. In other words, it may not be possible to mock non-interfaces.

Three Kotlin Multiplatform libraries for mocking are known to me, with a few comments from a short look at them, ordered by popularity on github:

Mockative

MocKMP

MockingBird

riQQ commented 1 week ago

I started to look into this. Here are some preliminary research results:

Mockative

MocKMP

MockingBird

westnordost commented 1 week ago

Nice! Many thanks for the deep research! Very cool that you even found a bug in the (it looks like) otherwise seemingly most fitting library, and also created a PR. We will see how the maintainer handles these.

With Mockative, are only classes mockable that are annotated with @Mockable?

riQQ commented 1 week ago

There's a way to do it without the attribute, but it might not work. (Side note: the attribute is only necessary for all classes that are not open. But currently there are quite a lot of them in StreetComplete)

If you prefer to make all classes in your project open (and thus also mockable by Mockative) without annotating them individually, you can adjust the allOpen configuration to apply to all classes. However, use this approach with caution, as it may have unintended side effects by making all your classes non-final.

allOpen {
    annotation("kotlin.Metadata")
}

source

westnordost commented 1 week ago

I see, so maybe just using interfaces might be the cleanest solution. Even though it will lead to some boilerplate code, there is at least not black magic involved. (But this decision can certainly be postponed until the time when we actually have a KMP setup and migrate the tests from javaTest to commonTest. Theoretically, we could just keep all the tests in jvmTests, too)