JMock and return Values

A colleague was working on a unit test the other day, and couldn’t figure out why it wasn’t working correctly. At a high level, here’s the testing code.

List<String> strings = new ArrayList<String>();
strings.put("value");

ListLikeAPIObject mockObject = mock(ListLikeAPIObject.class);

context.checking(new Expectations() {{
	exactly(2).of(mockObject).iterator();
		will(returnValue(strings.iterator());
}}

and this is the code in the class under test:

ListLikeAPIObject listObject = apiCallToGetList();
	for(Iterator iter = listObject.iterator(); iter.hasNext();) {
		doSomething();
	}

and the above method gets called twice during execution of the method being tested.

On the second call to listObject.iterator(), the for loop doesn’t do anything.

JMock ‘caches’ the result of the returnValue option, and returns the same object each time that method expectation is reached. The first time it’s called, strings.iterator() is at the beginning.

The next time it’s called, the iterator is now at end, so the for loop doesn’t process anything.

JMock2 has a built-in return Action for handling this case. There are several others defined (look at implementors of Action), and shortcut methods defined on Expectations. Taking advantage of this results in the following:

context.checking(new Expectations() {{
	exactly(2).of(mockObject).iterator();
		will(returnIterator(strings));
}}

The returnIterator constructs a ReturnIteratorAction. The ReturnIteratorActions stores the collection, and then calls strings.iterator() everytime the mocked method is called.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply