One method I've found pretty useful for testing asynchronous methods is injecting an Executor
instance in the object-to-test's constructor. In production, the executor instance is configured to run asynchronously while in test it can be mocked to run synchronously.
So suppose I'm trying to test the asynchronous method Foo#doAsync(Callback c)
,
class Foo {
private final Executor executor;
public Foo(Executor executor) {
this.executor = executor;
}
public void doAsync(Callback c) {
executor.execute(new Runnable() {
@Override public void run() {
// Do stuff here
c.onComplete(data);
}
});
}
}
In production, I would construct Foo
with an Executors.newSingleThreadExecutor()
Executor instance while in test I would probably construct it with a synchronous executor that does the following --
class SynchronousExecutor implements Executor {
@Override public void execute(Runnable r) {
r.run();
}
}
Now my JUnit test of the asynchronous method is pretty clean --
@Test public void testDoAsync() {
Executor executor = new SynchronousExecutor();
Foo objectToTest = new Foo(executor);
Callback callback = mock(Callback.class);
objectToTest.doAsync(callback);
// Verify that Callback#onComplete was called using Mockito.
verify(callback).onComplete(any(Data.class));
// Assert that we got back the data that we expected.
assertEquals(expectedData, callback.getData());
}