There's a black box class which creates a Thread
using its constructor accepting an instance of Runnable
as the argument:
public class Service {
public static Task implements Runnable {
@Override
public void run() {
doSomeHeavyProcessing();
}
}
public void doAsynchronously() {
new Thread(new Task()).start();
}
}
I want to intercept the constructor call and get a reference to the passing Task
implementing Runnable
. This is the code so far:
@RunWith(PowerMockRunner.class)
@PrepareForTest(Service.class)
public class ServiceTest {
@Test
public void testService() {
ArgumentCaptor<Runnable> runnables = ArgumentCaptor.forClass(Runnable.class);
Thread thread = Mockito.mock(Trhead.class);
whenNew(Thread.class.getContructor(Runnable.class)).
withArguments(runnables.capture)).thenReturn(thread);
new Service().doAsynchronously();
System.out.println("all runnables: " + runnables.getAllValues());
for (Runnable r : runnables.getAllValues()) r.run();
// perform some assertions after the code meant to be executed in a new
// thread has开发者_开发百科 been executed in the current (main) thread
}
}
Test execution will print out:
all runnables: []
Is there a way of grabbing a reference to all Runnable
objects or Thread
objects returned by the constructor? I want to execute the asynchronous code either in the current (main) thread or join created threads and perform assertions.
First your code had some typo errors, and once corrected it didn't work when tried in the IDE. The code throws a VerifyError
about the Task
initialization. Making Task
public
helped.
Once every was alright, your code worked as expected, meaning your runnables were captured.
Although I would go for this stubbing syntax instead :
whenNew(Thread.class).withParameterTypes(Runnable.class)
.withArguments(runnables.capture()).thenReturn(mock);
You should investigate your real code to see if it got correctly stubbed.
精彩评论