JFace observable lists with JUnit and Mockito
When you are writing unit tests that use JUnit and Mockito frameworks that check what sort of changes has been applied to an observable collection, you can do that but only with a trick to satisfy Java compilation
A scenario
Let’s imaging we have a observable list of strings and the code under test is going to manipulate on it by addting two elements and we want to verify in our test that this is indeed the only operation that was performed on the list.
Note that we could assert the post-operation state of the list, but since it’s bservable and emits change notifications, simply checking end result might not be what we want. Imagin that there are listeners that update othere parts of the system based on change notification, so the amount and character of those might be perfectly reasonable field of concern in this case.
What will not work
This is what comes straigth away when you approach. We could hook some mocking objects into list change event
notification and records what’s happening right?
Let’d o it. IN the file MyListTest.java
:
@Test
public void someTestMethodHere()
{
IObservableList<String> myList = new WritableList<>();
ListDiffVisitor<String> visitor = Mockito.mock(ListDiffVisitor.class);
myList.addListChangeListener((ListChangeEvent<? extends String> e)->e.diff.accept(visitor));
// now code under test will do something with it, e.g
// addSomeItems(myList)
// and finally validate the code:
Mockito.verify(diffVisitor, Mockito.times(2)).handleAdd(Mockito.anyInt(), Mockito.anyString());
Mockito.verify(diffVisitor, Mockito.times(0)).handleRemove(Mockito.anyInt(), Mockito.anyString());
Mockito.verify(diffVisitor, Mockito.times(0)).handleReplace(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString());
}
Looks good, with a little problem, that the code will not compile.
The problem is repored by Java and says this:
Description Resource Path Location Type
The method accept(ListDiffVisitor<capture#1-of ? extends String>) in the type ListDiff<capture#1-of ? extends String> is not applicable for the arguments (ListDiffVisitor<String>) MyListTest.java /... line ... Java Problem ...
What works
Any attempts to overcome this problem with inline failed in my case, and the only neat solution I’ve found was to extend test class with temporary abstract class definition:
private abstract class StringListDiffVisitor<T extends String> extends ListDiffVisitor<T> {}
There is no need to define anything in this class, because we will onbly use it to replace the original mock definition with it:
StringListDiffVisitor visitor = Mockito.mock(StringListDiffVisitor.class);
That’s it. Now the line:
myList.addListChangeListener((ListChangeEvent<? extends String> e)->e.diff.accept(visitor));
succesfully compiles and test correctly do its job.