Situation
I was in a Java class and the teachers demonstrated a process like this:
- Build a Message Queue, and a
Subscriberclass. TheSubscriberwill consume Message Queue inputs and call a certain function inServiceclass. - Create a test where we
Mockito.spy()on theSubscriberclass and publish something into the Message Queue. Wait for 2 seconds, and verify ifServicemethod is actually called once.
Subscriber
The Subscriber has a function like this:
@Bean
public Consumer<InputVO> subscribeInput() {
return inputVO -> {
inputService.someMethod(inputVo);
};
}
The Test
The test, then, is basically like this:
@Autowired
InputSubscriber inputSubscriber;
@Autowired
StreamBridge streamBridge;
@MockBean
InputService inputService;
@Test
public void subscriberMethod_WillBeCalled_WhenInputReceived() throws InterruptedException {
InputSubscriber subscriberSpy = Mockito.spy(inputSubscriber);
doNothing().when(inputService).someMethod(any(InputVO.class));
InputVO expected = ...;
streamBridge.send("binding", expected);
TimeUnit.SECONDS.sleep(2);
verify(inputService, times(1)).someMethod(expected);
// will fail with unfinished mock error for below line.
// verify(subscriberSpy, times(1)).subscribeInput();
}
The above test then passed, but if we un-comment the last verify() there will always be exception. The actual exception is like this:
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at
(Here it writes the name and position of test function.)
Example of correct verification:
verify(mock).doSomething()
I tried my best to keep only the mandatory parts, if it's still too long or falls lacking informations please let me know.
Problem
Does spying with a message queue work?
- The test is run with annotations of
@SpringBootTestand@Import(TestChannelBinderConfiguration.class). So theSubscribershould be actually started right? Then when we publish the expectedInputVoto MQ, and Consumer inSubscriberclass consumes it, does the spy know? I googled around and seems like spy can only track behaviours directly called through it instead of the object being spied on.
- The test is run with annotations of
verify()the spy always throw exception during the class.- When we call
verify()onsubscriberSpyit always throw exception, and Mockito reports the reason asUnfinished Mockwhich says it expects the callee function afterverify(). But we already wrote it asverify(subscriberSpy, times(1)).subscribeInput();. The teachers said the reason might be that we mixed Spring MockBean and Spy together. (The spy is spying on an object that injected a@MockBean(Service).), but we never found out the actual reason behind this. I understand that this might be hard to answer because the codes are shortened, but a possible direction pointing on this issue is also welcome.
- When we call