How to mock an iterator ?

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