Based on guava-libraries example, I am using ListenableFuture.
I am using:
java 1.6
JDeveloper 11.1.1.6.0
guava-13.0.1.jar
junit-4.5.jar
easymock-3.1.jar
powermock-easymock-1.4.12-full.jar
I am trying to ensure that method under test is called in async mode.
My Manager.java code is:
...
public synchronized void refreshAsync(final String id) {
m_Log.entry(id);
ListeningExecutorService service =
MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
ListenableFuture<Details> getDetailsTask =
service.submit(new Callable<Details>() {
@Override
public Details call() {
System.out.println(Thread.currentThread().toString());
return MyCacheManager.getDetails(id);
}
});
Futures.addCallback(getDetailsTask ,
new FutureCallback<Details>() {
// we want this handler to run immediately after we push the big red button!
public void onSuccess(Details details) {
System.out.println("Success");
//TODO: publish event
}
public void onFailure(Throwable thrown) {
System.out.println("Failed");
//TODO: log
}
});
service.shutdown();
m_Log.exit("done async");
}
...
My test is:
@RunWith(PowerMockRunner.class)
@PrepareForTest( { Manager.class, MyCacheManager.class, TWResourceManager.class, Logger.class })
public class DetailsTests {
{
...
@Test (timeout = 4000)
public void refreshAsync_RequestedInAsyncMode_NoWaitForComplete() throws Exception {
// Creating nice mock - because we are not caring about methods call order
mockStatic(MyCacheManager.class);
// Setup
final int operationTimeMilis = 5000;
expect(MyCacheManager.getDetails(anyObject(String.class))).andStubAnswer(new IAnswer<Details>() {
public Details answer() {
try {
System.out.println("start waiting 5 sec");
System.out.println(Thread.currentThread().toString());
Thread.sleep(operationTimeMilis);
System.out.println("finished waiting 5 sec");
} catch (InterruptedException e) {
e.printStackTrace();
}
return Details.getEmpty();
}
});
replay(MyCacheManager.class);
replayAll();
ISchemaActionsContract controller = new TWManager();
controller.refreshSchemaDetailsAsync("schema_id");
// We need not to verify mocks, since all we are testing is timeout
// verifyAll();
}
}
When I am running / debugging the test - it is always failed on timeout. It seems that mocked method "MyCacheManager.getDetails" is called in "sync" mode.
But when I am calling same function from regular code / debug - it is running in async mode (I put Thread.sleep(10000) into MyCacheManager.getDetails method, and Manager.refreshAsync method is exited without waiting / be blocked.
Also, If I am changing the method to use regular FutureTask, test pass as expected.
...
Object res = null;
FutureTask task = new FutureTask(new Runnable() {
@Override
public void run() {
MyCacheManager.getDetails(id);
}
}, res);
m_Log.debug("async mode - send request and do not wait for answer.");
Executors.newCachedThreadPool().submit(task);
Any idea will be more then welcome! :)
Thanks!
MyCacheManager.getDetails(...)
will be called and my test will exit therefreshAsync()
method. At this point, I'll know that sleep done in "parallel" thread and does not blocking my main test => test finished *before timeout*. But if test will failed on timeout - I know that thread is *sleeping in "sync" way*, and I'll be back from refreshAsync() only after it finished. – evgenyl Nov 28 '12 at 13:03