Mocking an iterator is a little bit special since it uses dynamic hasNext() and next() methods. Different approaches can be used to do this but here 2 of them are described.
The first method uses the signature of Mockito's thenReturn(T...) method:
"iterator" should "be mocked thanks to varargs from Mockito's thenReturn method" in {
val mockedIterator = Mockito.mock(classOf[Iterator[Int]])
Mockito.when(mockedIterator.hasNext).thenReturn(true, true, false)
Mockito.when(mockedIterator.next()).thenReturn(1, 2)
var numbers: Seq[Int] = Seq()
while (mockedIterator.hasNext) {
numbers = numbers :+ mockedIterator.next()
println(numbers)
}
numbers should contain allOf(1, 2)
}
But the previous method is only possible when we know the number of values in advance. Another constraint is the ability to define these values by hand. It's easy for 3 possible entries but not so possible for 300. The next method solves this problem:
"iterator" should "be mocked thanks to delegation" in {
val inputNumbers = Seq(1, 2, 3, 4)
val numbersIterator = inputNumbers.iterator
trait WrappedIterator {
def getIterator: Iterator[Int]
def hasNext: Boolean
def next: Int
}
val wrappedIterator = Mockito.mock(classOf[WrappedIterator])
Mockito.when(wrappedIterator.getIterator).thenReturn(numbersIterator)
// Note that the ue of thenReturn(...) won't work because it will always return the 1st
// state of the iterator
Mockito.when(wrappedIterator.hasNext).thenAnswer((invocation: InvocationOnMock) => {
numbersIterator.hasNext
})
Mockito.when(wrappedIterator.next).thenAnswer((invocation: InvocationOnMock) => numbersIterator.next())
var numbers: Seq[Int] = Seq()
while (wrappedIterator.hasNext) {
numbers = numbers :+ wrappedIterator.next
}
numbers should contain allOf(1, 2, 3, 4)
}