Hi, everyone! How are you currently mocking for Ko...
# multiplatform
k
Hi, everyone! How are you currently mocking for Kotlin/Native tests? I'm using mockk but it's not for native. Right now, I'm just leaving it at that and waiting for native support but I want to put my tests in native and considering hand-writing fake classes just so I can achieve it. Is this something I should consider or is it better to wait for mockk's native support? Thanks in advance!
s
Fakes are always a better idea
k
Thanks for the response. How do you go about it? Seems like a ton of code to hand-write especially when you have to stub. You'd need to create a
FakeClassForCase1
,
FakeClassForCase2
, and so on or am I missing something in particular?
Okay, so I just thought about it and I figured I can make fake classes and add a stubbing behavior through variables. Now, the only thing I'm thinking about is how to not mark every class as
open
or create an interface for each of them.
a
Just write test implementations. E.g. test database, test network client etc. Don't verify that a method is called on your test class. Verify the output instead. E.g. that there are N entries in the database. Or an entry is updated with new values.
Personally I stopped using mocks even in normal Android projects.
k
Verifying behavior is exactly what I'm doing. For more context, I'm doing something like this:
Copy code
class MyViewModel(val useCase: UseCase)

class UseCase(val repository: Repository)

interface Repository

class RepositoryImpl(
    val localSource: LocalSource,
    val remoteSource: RemoteSource
)
With mocks, I can test
MyViewModel
with a
Copy code
// Setup
val useCase = mockk()
val viewModel = MyViewModel(useCase)

// Stub
coEvery { useCase() } returns ...

// Then do whatever assertion I need
I understand creating fakes for the
Repository
and just use a
Map
for caching or whatever but when it comes to
MyViewModel
and
UseCase
seems like I'd need to create an interface for each use case or mark each and every one of them as
open
so I can create fake test implementations.
a
So in your case you will need to extract an interface for your use case and then write a test implementation of it. Then later, if you change the use case you will need to just update its test implementation.
k
That seems like an expensive cost just to introduce testing. With mocks, I can test them as is. If I have 20 use cases, there'd be 20 test implementations
For each use case, I'd have to maintain the production code, the unit test, the interface, and then the test implementation.
a
Well it's questionable. Mocking classes is probably a bad idea. Since it still contains real code than might work and affect your tests. Also depending on a concrete implementation violates soliD.
You will have to maintain more code if you use mocks. Because mocks are copy-paste of the production code. If you read the article you will find out 😀
Any way that's what we have. You have to use interfaces to test Kotlin Native. 🙃
k
I'm considering on just creating fakes for my repositories and test the view models and use cases together.
Copy code
val fakeRepo = FakeRepo()
val useCase = UseCase(fakeRepo)
val viewModel = MyViewModel(useCase)
Then perform tests against it but it seems like I coupled the view model and use case and it becomes an integration test rather than a unit test. Right now, I can't see the benefit of making fakes for use cases.
Yeah. I guess I have to if I want to achieve it. I'll still be on the lookout for other solutions. That might be my last resort. I'm thinking on making every use case an
open class
instead just so I skip the interfaces. Not sure if it's a good idea though. Thanks for your inputs! It's very much appreciated!
c
Isn't there a compiler plugin from JetBrains to make classes open? They made it for Spring but you might be able to use it only for your testImplementation somehow. I believe it was called
all-open
For all the ideological reasons against mocking libraries, it is really convenient and in some cases necessary. There are the small handful of cases where you need to spy and then fakes might not suffice (unless I'm missing something). Plus fakes are more code. That said, for multiplatform in my opinion fakes are more suitable.