Dear MockK, Repeat After Me
Thursday, January 16, 2020 |The project I’m working on is using Mockk in the unit tests. It’s a great library that has made true unit testing so much easier. I ran into a problem, though, where I needed a method I was mocking to return the value it was receiving. To be more specific, we were passing an object to a Spring repository method that had been built inside the method to test, and, to test thoroughly, I needed to get to that object. Turns out, that’s pretty easy to do with Mockk. Let’s take a look…
First, a clear set up. The code basically looks like something like this:
1
2
3
4
5
6
7
8
9
10
11
12
@PostMapping("/foo")
fun post(@RequestBody foo : Foo) : Bar {
val bar = Bar()
bar.prop1 = foo.prop1
bar.prop2 = calculatedValue(foo)
var newBar = repository.save(bar)
// Do some more work with newBar
return newBar
}
For the purposes of the test, I don’t much care about the "Do some more work" part. I need the return value of
repository.save()
. I set up the test like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
fun testCreateFoo() {
val barSlot = slot<Bar>()
every { repository.save(capture(barSlot)) } answers { barSlot.captured }
val result = mockMvc.perform(MockMvcRequestBuilders
.post("/foo")
// ...
val savedBar = gson.fromJson(result.response.contentAsString, Bar::class.java)
assertThat(savedBar.prop2).isEqualTo(expectedValue)
}
The interesting part is the call to every
. Using a CapturingSlot<T>
, I instruct the
system to capture the Bar
that the method under test passes in, and I simply return it in the lambda I pass to
answers
. It is true that we don’t have access to the what the repository might do to the Bar instance (filling in
related objects, etc.), but that’s OK. I just want to look at the value of prop2
, and this lets me do that
nice and neat. :)