You could make the consumer invoked by forEach()
a settable field:
private Consumer<Item> processingAction = this::processItem;
public void setProcessingAction(Consumer<Item> action) {
this.processingAction = action;
}
public void doSomething(Collection<Item> batch) {
batch.stream()
.filter(item -> item.group_id == 1)
.forEach(processingAction);
}
Now your test can be:
objUnderTest.setProcessingAction( item -> assertThat(item.groupId, is(1)));
objUnderTest.doSomething(listContainingItemsFromOtherGroups);
No need for Mockito here - your test-double is a lambda. You can, of course, mock a Consumer<Item>
if you prefer.
It's a bit of a smell having a method just for testing (setProcessingAction()
) - but that's because of the hard-coding and tight-coupling you've chosen to do. Why not take the opportunity to make injection (possibly constructor-injection) the primary way of setting the action?
If you're unwilling to make the action injectable, then you're stuck with processItem()
always being called, and the effects of processItem()
will be the only way to know what items were filtered.