What's the conventional wisdom on mockito-kotlin v...
# announcements
t
What's the conventional wisdom on mockito-kotlin vs MockK? I feel like mockito-kotlin is more intuitive
m
Don't know about conventional, but this has been my approach. But bottom-line, they are both excellent, and more alike than different. If you work with both Java and Kotlin, I'd suggest sticking with Mockito as you can leverage knowledge you already have, and reduce training effort of people joining a mixed team. If you're mostly/all Kotlin, and want to test some of the features MockK supports, then use it. If you want your tool chain as Kotlin as possible, then again, choose MockK.
t
What does MockK do better than mockito-kotlin and vice versa? From what I can tell they are both absolute crap or maybe I'm just too stupid to use them. Mockito-kotlin simply crashes when you wrap a matcher in
not()
which means you can't verify that an argument is not equal to something with using
argWhere { ... }
. MockK's API is completely asinine. Who thought
verify(exactly = 1, atLeast = 2)
would be a good idea? MockK also lacks Mockito's
check
matcher. And neither seem to allow me to verify that all calls to a function satisfy a predicate. Mockito has
verifyAll
of course but that applies to all methods and not just one. So for an n-argument method you end up writing n+1 separate
verify
clauses: One to verify the positive case and n to verify the negative case for each argument.
m
I'll be blunt. I don't think your approach is the best. You're creating too tight a coupling between the tests and the implementation. You should be testing the inputs, and outputs, and not care too much how the called function is doing its thing. Otherwise you can't safely refactor the implementation as you're changing both the test and the implementation. Having said that, Mockito can come closer to what I think you want if you're using JUnit4/5, and you use the Mockito Rule/Extension and Strict verification of mocks. Basically, if you define a mock, and an interaction on it, then the extension will ensure that ALL defined interactions are called, and that ONLY the defined interactions were called. If you define a mock, but NO interactions on it, then Mockito won't do the above verifications. So that's an edge case to be aware of. But I believe there's a 'noMoreInteractions' for that scenario. I don't think MockK supports that level of strictness right now. HTH
Just re-reading. Have you seen the 'noMoreInteractions' function on Mockito? I think that's exactly what you're looking for and will work regardless of test framework. https://mincong.io/2019/09/22/mockito-verify/#verify-interaction-with-other-methods Of course author has same opinion I do:
Personally, I don’t recommend this kind of verification because it is too strict: it means that you don’t trust the actual implementation and the test needs to be updated frequently, every time when more interaction is added with the target mock object.
t
verifyNoMoreInteractions
won't work here because it also excludes calls to other methods of the mock. I want to verify: any number of calls to any method except
foo
and at least one call to
foo
with parameter
x
and for all calls to
foo
parameter is
x
. Or in pseudocode:
Copy code
val callsToFoo = calls.filter { it.methodName == "foo" }
assert(callsToFoo.all { it.argument == "x" } && callsToFoo.size >= 1)
Another thing about MockK: Why is there both
verify(inverse = true)
and
verify(exactly = 0)
. Shouldn't they be the same?
m
I'm not real familiar with MockK, but guessing you can define some mock interactions, but put
inverse = true
and it would ensure that those aren't called. And because of possible parameters, you'll just end up with some equivalencies.
Can you do something like this?
Copy code
//argument matchers can also be written as Java 8 Lambdas
 verify(mockedObject).foo(argThat(someString -> someString == "X"));
From: https://javadoc.io/static/org.mockito/mockito-core/3.2.4/org/mockito/Mockito.html#argument_matchers
e
If you ask for opinions, here's mine: I think MockK is more intuitive, because it leads to more idiomatic Kotlin which arguably is more intuitive.
Note that MockK also has something similar to
verifyNoMoreInteractions
, called
confirmVerified
. You can verify that you've verified all recorded interactions with your mocks.
t
You can use
argThat
instead of
not
but it's not really convenient
confirmVerified
wont work because I only want to verify all interactions on one method not on all methods
k
I prefer MockK. The criticisms I’m seeing above of MockK should properly be classified as “fails to protect a stupid dev from themselves” rather than “does stupid stuff itself.” I write only in Kotlin, never in Java, and I kept running into things where Mockito couldn’t do something I needed it to do. It’s been a few months now, so I can’t remember what they were.
e
Agreed. If testing and writing testable code are done correctly, then MockK is a great tool to do the mocking. With any mocking lib, be it Mockito or MockK or any other, you can simply do it wrong and end up testing that you've set up your mocks correctly, instead of testing your testable code's behaviour.
t
IMO a library should be designed to make misuse impossible and to be discoverable without documentation. Neither Mockito nor MockK fulfill these criteria unfortunately.
m
That's a good ideal, but unfortunately when it comes to testing, there isn't a concrete definition of 'misuse', or 'good use'. So if the library wants to be used, it unfortunately ends up being too flexible, and requires team guidelines/rules...
338 Views