I'm running into a problem with trying to set up a Mockery to test for method invocation. I saw How to test protected methods of abstract class using JUnit and JMock and it's essentially the same question, but I can't make out what Chris is referring to in his answer. If I could please have someone explain it to me in a slightly different way or with more complete English. I'm using JUnit, JMock2, Infinitest (if that matters), and a standard event-based message system as follows:
public Interface MyEventListener {
void handleMyEvent(MyEvent e);
}
public Class MyEvent extends EventObject {
public MyEvent(Object source) {
super(source);
}
}
public Class MySource {
protected List<MyEventListener> listeners = new ArrayList<MyEventListeners>();
public void addListener(MyEventListener listener) {
listeners.add(listener);
}
public void removeListener(MyEventListener listener) {
listeners.remove(listener);
}
// other code...
protected void raiseEvent() {
for (MyEventListener listener : listeners) {
listener.handleMyEvent(new MyEvent(this));
}
}
}
Now here's my test:
@Test
public void sourceShouldThrowEventOnEventOccurrence() {
// set up
Mockery context = new Mockery();
MyEventListener listener = context.mock(MyEventListener.class);
MySource source = new MySource();
MyEvent event = new MyEvent(source);
source.addListener(listener);
// set expectations
context.checking(new Expectations() {{
oneOf(listener).handleMyEvent(event);
}});
// execute
// do stuff to (theoretically) raise event
// verify
context.assertIsSatisfied();
}
I get an ExpectationError (unexpected invocation) on my protected method of raiseEvent() in MySource. How can I add to the expectation that it should call the protected method?
Also, a thought just occurred to me - but I'm still posting this message before I go explore it (in case someone else has the same question and my thought ends up being right or not). Could the error possibly be related to the fact that I have two new keywords in my code? I have new MyEvent(this) in MySource.raiseEvent() and then I have new MyEvent(source) in the test. This creates two different events in memory... Is the error related to the possibility that it expects the method to get one event, but receives the other?
*****EDIT
Actually, specifically, I get an ExpectationError (unexpected invocation) on the line of code that actually raises the events. (In my code above, the listener.handleMyEvent(new MyEvent(this));
line)
It turns out my suspicion that it was related to the fact that two different MyEvent instances were being created was correct. Unfortunately, it means the title to my question is misleading. After digging, I found out that my code worked fine once I changed my Expectations() to the following.
@Test
public void sourceShouldThrowEventOnEventOccurrence() {
// set up
Mockery context = new Mockery();
MyEventListener listener = context.mock(MyEventListener.class);
MySource source = new MySource();
// MyEvent event = new MyEvent(source); <-- NO LONGER NEEDED
source.addListener(listener);
// set expectations
context.checking(new Expectations() {{
oneOf(listener).handleMyEvent(with(any(MyEvent.class))); // <-- with any
}});
// execute
// do stuff to (theoretically) raise event
// verify
context.assertIsSatisfied();
}