lupuuss / Mokkery

The mocking library for Kotlin Multiplatform, easy to use, boilerplate-free and compiler plugin driven.
https://mokkery.dev
Apache License 2.0
124 stars 6 forks source link

Mocking `abstract`/`open` classes requires default constructor #5

Open lupuuss opened 1 month ago

lupuuss commented 1 month ago

Currently, Mokkery requires abstract/open classes to have a default constructor, and it should be possible to remove this requirement.

This limitation was partially mentioned in #4 .

Nillerr commented 2 weeks ago

Hi @lupuuss!

Happy to have come across another mocking framework for Kotlin Multiplatform!

The way we solved this in mockative/mockative was by recursively generating mocks (and default values) for the parameters of the default constructor. This also automatically enables implicit chain-mocking like this:

interface LibraryClient {
    val books: BooksRepository
}

val client = mock<LibraryClient>()

@Test
fun test() {
    everySuspend { client.books.findById(id) } calls { (id: String  -> Book(id) }
} 

This assumes the consumer is also using the all-open plugin. You may be able to do something similar in your Mokkery 🙂

lupuuss commented 1 week ago

Hi @Nillerr!

Thank you for your kind words and the suggestion! I've started investigating this feature some time ago, and I think providing a default value for each parameter is sufficient to make it work and generating mocks recursively seems like an overhead. Also, reusing it for the chain-mocking would still require extra effort to make this feature work. Moreover, I'm not sure if implementing chain-mocking is worth the effort as the syntax below might be "good enough":

every { client.books } returns mock {
    everySusend { findById(any()) } calls { (id: String) -> Book(id) }
}

What do you think about it?