I'm trying to test a workflow that has an asynchronous method - setup roughly looks like this:
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class testWorkflow {
@Rule
public WorkflowTest workflowTest = new WorkflowTest();
@Mock
protected Activities mockActivities;
@Before
public void setUp() throws Exception {
workflowTest.addActivitiesImplementation(mockActivities);
workflowTest.addWorkflowImplementationType(Workflow.class);
workflow = workflowFactory.getClient();
}
@Test
public void testMethod1Exception() throws Throwable {
doThrow(new RuntimeException("bang!"))
.when(mockActivities).method1();
try {
runWorkflow();
fail();
} catch (Exception e) {
verify(mockActivities, never()).method2();
}
}
private void runWorkflow() throws Throwable {
AsyncScope scope = new AsyncScope() {
@Override
protected void doAsync() {
workflow.run();
}
};
scope.eventLoop();
if (!scope.isComplete()) {
System.out.println(scope.getAsynchronousThreadDumpAsString());
}
}
}
My problem is in my code the workflow looks roughly like this:
public class Workflow {
public void run() {
final Promise<Result> pResult = client.method1();
doAsync(pResult);
}
@Asynchronous
public void doAsync(Promise<Result> pResult) {
...
}
}
I found that the unit test hits the fail()
call. Reading the output of the getAsynchronousThreadDumpAsString
method seems to indicate that the workflow is waiting on pResult
being available for the @Asynchronous
method, however it doesn't become available because I threw the exception. Is there any way to get a test like this to work? The actual test I am trying to get to work is testing how code behaves in a doCatch
block, but the workflow seems to freeze due to the @Asynchronous
method call.
I believe the problem is that you use both AsyncScope and WorkflowTest rule at the same time. WorkflowTest already executes @Test method in an AsyncScope, so another AsyncScope might confuse it. I would rewrite your code like:
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class testWorkflow {
@Rule
public WorkflowTest workflowTest = new WorkflowTest();
@Mock
protected Activities mockActivities;
@Before
public void setUp() throws Exception {
workflowTest.addActivitiesImplementation(mockActivities);
workflowTest.addWorkflowImplementationType(Workflow.class);
workflow = workflowFactory.getClient();
}
@Test
public void testMethod1Exception() throws Throwable {
doThrow(new RuntimeException("bang!"))
.when(mockActivities).method1();
new TryCatchFinally() {
Throwable failure;
protected void doTry() {
workflow.run();
}
protected void doCatch(Throwable e) {
failure = e;
}
protected void doFinally() {
assertNotNull(failure);
}
};
}
}
But in reality even all of the above is not necessary when using expected:
@RunWith(FlowBlockJUnit4ClassRunner.class)
public class testWorkflow {
@Rule
public WorkflowTest workflowTest = new WorkflowTest();
@Mock
protected Activities mockActivities;
@Before
public void setUp() throws Exception {
workflowTest.addActivitiesImplementation(mockActivities);
workflowTest.addWorkflowImplementationType(Workflow.class);
workflow = workflowFactory.getClient();
}
@Test(expected=RuntimeException.class)
public void testMethod1Exception() throws Throwable {
doThrow(new RuntimeException("bang!"))
.when(mockActivities).method1();
workflow.run();
}
}
Code inside @Test methods is executed in a context of a dummy workflow. That's why, for example, inside tests workflow is created using normal client and not external one.