Mocking is not rocket science: Expected behavior and behavior verification
source link: https://blog.kotlin-academy.com/mocking-is-not-rocket-science-expected-behavior-and-behavior-verification-3862dd0e0f03?gi=da110e52c9a6
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Mocking is not rocket science: Expected behavior and behavior verification
In the previous article, I described basics of mocking. Now let me do an overview of basic features of MockK.
Calls to Dependent-On Component can be pretty sophisticated. That is why sometimes you need to provide sophisticated expected behavior. There are two things helping you to do that: argument matchers and expected answers.
Argument matcher is an argument placeholder specifying which variety of values are acceptable for an argument in
every
andverify
constructs.The expected answer is an answer that the call is returning upon usage in System Under Test.
Argument matching
For example, you have mocked DOC with call(arg: Int): Int
function. You want to return 1
if argument is greater than 5
and -1
if it is less or equal to 5
. This can be achieved by following construct:
every { mock.call(more(5)) } returns 1
every { mock.call(or(less(5), eq(5))) } returns -1
more
, less
, eq
and or
are argument matchers. You can check the full list of them in the documentation. For most situations, it should be enough, but of course, you can create your own, either by sub-classing or via lambda function.
On the contrary, to argument matching in Mockito, it is not required to specify all argument matchers for all arguments. You can leave some arguments a fixed value. If you leave matcher a fixed value it is automatically wrapped in eq
matcher.
every { mock.call(more(5), 6) } returns 1// is same asevery { mock.call(more(5), eq(6)) } returns 1
Expected answer
Answers define a behavior of the mocked method. The simplest answer is returns
. We already observed it in the previous example. Provided value is fixed and returned every time call is matched.
returnsMany
specify a number of values that are used one by one i.e. first matched call returns first element, second — second element, e.t.c.
every { mock1.call(5) } returnsMany listOf(1, 2, 3)
You can achieve the same using andThen
construct:
every { mock1.call(5) } returns 1 andThen 2 andThen 3
throws
throw an exception if the call is matched.
every { mock1.call(5) } throws RuntimeException("error happened")
just Runs
should be used in case return value is Unit
.
every { mock1.callReturningUnit(5) } just Runs
answers
allow specifying custom lambda function returning an answer.
every { mock1.call(5) } answers { arg<Int>(0) + 5 }
arg<Int>(0)
stands for the value of the first argument in an intercepted call. There is a bunch of such properties and functions available in the scope of answer lambda. This helps build sophisticated custom answers. Full list is available in the documentation.
Behavior verification
Here is an extension of example from the previous article. This mocks behavior of DOCs, checks SUT and verifies DOCs were called.
Starting from this point when we add verification it can be called mocking as a term coined in industry. Read more about it here.
@Test
fun calculateAddsValues() {
val doc1 = mockk<Dependency1>()
val doc2= mockk<Dependency2>()
every { doc1.value1 } returns 5
every { doc2.value2 } returns "6"
val sut = SystemUnderTest(doc1, doc2)
assertEquals(11, sut.calculate()) verify {
doc1.value1
doc2.value2
}
}
Behavior verification checks that mocked Dependent-On Components were called. This checks should be placed at the end of the test, after checking System Under Test.
There are basically four types of verification supported: unordered
, ordered
, sequential
and all
.
Unordered verification guarantees that calls were happening without regard to order. For example, you would like to check if call(5)
happened at least once.
verify { mock1.call(5) }
Unlike inevery
, in verify
block, you can have several calls going one after another.
verify {
mock1.call(5)
mock1.call(6)
}
This checks that call(5)
and call(6)
happened at least once.
verify
can have parameters. atLeast
, atMost
specify how much verified calls happening. By default, atLeast
is 1
and atMost
is Int.MAX_VALUE
which effectively means we expect call happen at least once.
verify(atLeast = 5, atMost = 7) {
mock1.call(5)
}
This checks that call(5)
happened at least 5
and at most 7
times.
exactly
parameter sets both atLeast
and atMost
to the same value.
verify(exactly = 5) {
mock1.call(5)
}
This checks call(5)
happened exactly 5 times.
Specifying exactly = 0
you can verify call did not happen at all:
verify(exactly = 0) {
mock1.call(5)
}
Sometimes you want to check if mocked DOC was not called at all. This can be achieved with special wasNot Called
construct. It is equivalent to verifyZeroInteractions
in Mockito.
verify {
mock1 wasNot Called
}
That is basically it for unordered verification.
verifyAll
is doing same as verify
, except it additionally checks that all matched calls are the only calls happened to mentioned mocks. This is similar to verifyNoMoreInteractions
in Mockito.
verifyAll {
mock1.call(5)
}
Next two types of verification areverifyOrder
and verifySequence
. They check the order of happened calls.
The difference is that verifySequence
checks order and that all the matched calls are the only calls happened to mentioned mocks. That way it verifies the exact sequence of calls.
For example, let we have calls happened in SUT:
mock1.call(1)
mock1.call(2)
mock1.call(3)
To verify that the exact sequence happened you need to write following:
verifySequence {
mock1.call(1)
mock1.call(2)
mock1.call(3)
}
verifyOrder
on other hand verifies only the order of calls that happened, allowing gaps in the sequence of calls.
verifyOrder {
mock1.call(1)
mock1.call(3)
}
This checks that call(1)
happened before call(3)
.
These are the most basic features of MockK you should know, in next articles we’ll move on to more advanced things.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK