Use Object.wait()
We have worked with some asynchronous processes that obtain files from directories or .ZIP archives. We use the content of the files somewhere else while the asynchronous one keeps on reading.
The way we came around to test them was to wait()
on the communication object --in our case it was a Queue--, so the asynchronous process would queue.notifyAll()
whenever there was a new file ready to be used and kept working. On the other end the consumer would process one item at a time until the queue was empty and then queue.wait()
to wait for more. We do use a special object passed through the queue to indicate that there are no more items to process.
In your case I suppose the object you want to check, objectToRoute,
is not really created inside the method you want to test. You could wait()
on it inside the test, and notifyAll()
on it inside the method you want to test, methodToBeTested.
I know this would introduce the extra line of code in your production code base, but with nobody waiting on it, it should result harmless. It would end up something like:
public void methodToBeTested(Object objectToRoute) {
if (someConditions) {
routingService.routeInOneWay(objectToRoute);
} else {
routingService.routeInAnotherWay(objectToRoute);
}
synchronized(objectToRoute) {
objectToRoute.notifyAll();
}
}
And in your test class there will be something like:
@Test
public void testMethodToBeTested() throws InterruptedException {
Object objectToRoute = initializeObjectToRoute();
methodToBeTested(objectToRoute);
synchronized (objectToRoute) {
objectToRoute.wait();
}
verifyConditionsAfterRouting(objectToRoute);
}
I do know that in this simple example does not make too much sense, since the sample system is not multithreaded. I assume the multithread twist is added in the routeInOneWay
and routeInAnotherWay
methods; thus, those are the ones to call notifyAll()
method.
As sample code to point the direction of our solution, here are some code fragments.
In the asynchronous worker side, or producer:
while(files.hasNext(){
queue.add(files.next());
synchronized (outputQueue) {
queue.notifyAll()
}
}
And in the consumer side:
while(!finished){
while(!queue.isEmpty()){
nextFile = queue.poll();
if (nextFile.equals(NO_MORE_FILES_SIGNAL)) {
finished = true;
break;
}
doYourThingWith(nextFile);
}
if (!finished) {
synchronized (outputQueue) {
outputQueue.wait();
}
}
}