104

Mocking is not rocket science: Expected behavior and behavior verification

 6 years ago
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.

1*WjGApuQKNxEpbqmuNHg-_g.jpeg

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 and verify 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): Intfunction. 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
1*LByADZj4wpCgGRU8wwikVA.jpeg

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.

1*g__uxXcU0-HA_OJRfCkxtw.jpeg

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).

1*DpCi1Kdt7P_BbGpiho6wbQ.jpeg

These are the most basic features of MockK you should know, in next articles we’ll move on to more advanced things.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK