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

Use multiplatform mocking library for tests #5420

Open
westnordost opened this issue Dec 20, 2023 · 7 comments · May be fixed by #5706
Open

Use multiplatform mocking library for tests #5420

westnordost opened this issue Dec 20, 2023 · 7 comments · May be fixed by #5706
Assignees
Labels
iOS necessary for iOS port

Comments

@westnordost
Copy link
Member

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

  • multiplatform support for at least Java/Android and iOS

  • stable, well-tested and ideally (semi-)official / well-maintained

  • support all features of Mockito we are using now

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

  • seems well maintained
  • good documentation
  • has a guide how to migrate from Mockito to Mockative and apparently also a similar API to Mockito

MocKMP

  • seems well maintained
  • good documentation
  • backed by a company (Deezer)

MockingBird

  • seems well maintained
  • from a quick glance, API seems to be a bit inconvenient
  • oldest library, i.e. started in 2021, the others in 2022
@westnordost westnordost added the iOS necessary for iOS port label Dec 20, 2023
@westnordost westnordost moved this to Blocked in iOS Port Dec 20, 2023
@westnordost westnordost moved this from Blocked to Todo in iOS Port Dec 20, 2023
@riQQ
Copy link
Collaborator

riQQ commented May 5, 2024

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

Mockative

MocKMP

  • can only mock interfaces and create fakes of concrete trees, i.e. can't fake a class with an interface typed property.
    (source)
  • requires KMP, compiler error on current StreetComplete head because KMP isn't used yet
  • single maintainer and barely any other contributors. Built in collaboration with Deezer according to the readme.
  • issues with Kotlin 2 / KSP2: Support Kotlin 2.0 kosi-libs/MocKMP#77. Also describes the disadvantage of a compiler plugin over using KSP.

MockingBird

  • can only mock interfaces
  • documentation is a bit confusing about the setup for the code generation. There are two options.
  • three contributors with >10 commits from the same company (Careem), barely any recent activity, seems to be feature complete / maintenance only (source)
  • no work on Kotlin 2 / KSP2 yet

Mokkery

  • compiler plugin based (the others are symbol processing (KSP) based)
  • limitations
    • Only abstract/open classes with no-args constructor

@westnordost
Copy link
Member Author

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
Copy link
Collaborator

riQQ commented May 5, 2024

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
Copy link
Member Author

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)

@westnordost westnordost moved this from Todo to In Progress in iOS Port Jul 16, 2024
@FloEdelmann FloEdelmann linked a pull request Jul 20, 2024 that will close this issue
@riQQ
Copy link
Collaborator

riQQ commented Aug 28, 2024

The comment in mockative/mockative#100 (comment) of the main maintainer of Mockative is sadly not inspiring confidence in the continued development and support of Mockative for Kotlin 2.


Mokkery has seen a lot of development in the last months and looks promising in this regard. And it already has support for Kotlin 2.

But I still have to check it out and see if it has all the features we need for the tests.

@westnordost
Copy link
Member Author

Hm, this is sad, as you've put so much effort into integration with Mockative already. Both Mockative and MocKMP seem to have the same issue with K2. I do wonder whether the maintainers of these two libraries know of Mokkery? Maybe they want to take a similar approach with making their libraries K2-compatible. Then on the other hand, I don't know how bug such a mocking library is. Maybe if they would do that, they would just end up having a Mokkery in green.

@riQQ
Copy link
Collaborator

riQQ commented Aug 28, 2024

The maintainer of Mockative knows of Mokkery. They commented about it somewhere in the Mockative issues, that's how I found Mokkery in the first place. They also commented on a Mokkery ticket about recursive / chain mocking.

MockKMP seems to be dead / unmaintained.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
iOS necessary for iOS port
Projects
Status: In Progress
Development

Successfully merging a pull request may close this issue.

2 participants