2

Say I've got this code:

public void doSomething(Collection<Item> batch)  { 
   batch.stream()      
   .filter(item -> item.group_id == 1)      
   .forEach(this::processItem);
}

processItem() is private method.

In real life the filter is more complex. I want to construct a unit test to verify a Collection items that all should fail the filter check, will result in forEach() never being invoked.

2 caveats:

  • Cannot modify doSomething() method signature
  • Prefer to keep processItem() private void method
Ray
  • 40,256
  • 21
  • 101
  • 138

3 Answers3

3

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.

slim
  • 40,215
  • 13
  • 94
  • 127
  • This sounds reasonable, test the effects on things I control like mocks used by `processItem()` – Ray Aug 23 '17 at 15:56
  • @Ray sorry, I had a brainwave and changed my answer. – slim Aug 23 '17 at 15:58
  • 1
    Passing the processor as a dependancy makes sense, I could keep the `doProcessBatch()` signature that way and also keep processor hidden. – Ray Aug 23 '17 at 16:00
0

Option 1:

Make the processItem method package-private and check it was never called.

Option 2 (preferred in my opinion):

Switch from forEach to map, and make sure the resulting stream/collection is empty.

Florian
  • 140
  • 7
  • Ideally looking to not change access of processItem. Cannot alter method signature of `doSomething()`, but that may be only recourse – Ray Aug 23 '17 at 15:25
0

Thinking out of the box, can you mock something that's called inside processItem and verify that that's not called?

That'd have the same effect as verifying processItem isn't called.

jwenting
  • 5,505
  • 2
  • 25
  • 30