Reputation: 3119
I'm using Mockito in kotlin to check that a list is paged correctly
I use this code
logic.searchItems(filter)
verify(vm).setItems(all.subList(0, 10), true)
logic.loadNext()
verify(vm).setItems(all.subList(0, 20), true) (1)
logic.loadNext()
verify(vm).setItems(all.subList(0, 30), true) (2)
In theory this should work, but I get too many invocations exception in (1) and (2).
If I use times(1) in (1) and times(2) in (2) the test passes. But I wish to verify that that method is called with those specific arguments.
Can this be done with Mockito?
Upvotes: 3
Views: 103
Reputation: 3119
After some testing I figured out that the problem was that in my logic I added the results to the same list before sending them back like so:
addItems(results:List<Item>()){
//verifications here
myItems.addAll(results)
vm.setItems(myItems,true)
}
this for some reason made mockito think it was the same invocation?
when I do it like this it works
addItems(results:List<Item>()){
//verifications here
myItems.addAll(results)
vm.setItems(myItems.map { it.copy() },true)
}
I do not know if it is a bug, or the intended behaviour, but at least this works
edit:
Ok so I feel like an idiot because it is not a bug at all, it is indeed the intended behaviour, and it saved me some future trouble
when using captors, I figured out that when the setItems
method is called Mockito keeps a reference to the returned list.
the next time it is called I used to add items to myItems and Mockito kept the new reference
but since I performed an addAll
operation the reference that was previously kept also got updated, so it is indeed normal that Mockito needs the times(2) method when I call it because the list it got in the first invocation was updated and will match the second list.
the correct way it seems, is to send a copy of that list, that way the viewModel can't alter the original list in any way
Upvotes: 1
Reputation: 26502
With this kind of parameters, being a Collection with specific content I would advise using the ArgumentCaptor
feature. Thanks to that you will be able to capture the passed parameters and later assert their value / state using tools like Hamcrest or AssertJ:
final ArgumentCaptor<List> captorListOne = ArgumentCaptor.forClass(List.class);
final ArgumentCaptor<List> captorListTwo = ArgumentCaptor.forClass(List.class);
final ArgumentCaptor<List> captorListThree = ArgumentCaptor.forClass(List.class);
verify(vm).setItems(captorListOne.capture(), true)
logic.loadNext()
verify(vm).setItems(captorListTwo.capture(), true)
logic.loadNext()
verify(vm).setItems(captorListThree.capture(), true)
List listToAssert = captorListOne.getValue();
...
More the ArgumentCaptor
Upvotes: 0