使用@Asynchronous 方法对 SWF 进行单元测试

Unit testing SWF with @Asynchronous methods

我正在尝试测试具有异步方法的工作流 - 设置大致如下所示:

@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());
        }
    }
}

我的问题出在我的代码中,工作流程大致如下所示:

public class Workflow {
    public void run() {
        final Promise<Result> pResult = client.method1();
        doAsync(pResult);
    }

    @Asynchronous
    public void doAsync(Promise<Result> pResult) {
       ...
    }
}

我发现单元测试命中了 fail() 调用。读取 getAsynchronousThreadDumpAsString 方法的输出似乎表明工作流正在等待 pResult 可用于 @Asynchronous 方法,但它不可用,因为我抛出了异常。有没有办法让这样的测试起作用?我试图开始工作的实际测试是测试代码在 doCatch 块中的行为方式,但由于 @Asynchronous 方法调用,工作流程似乎冻结了。

我认为问题在于您同时使用了 AsyncScope 和 WorkflowTest 规则。 WorkflowTest 已经在 AsyncScope 中执行 @Test 方法,因此另一个 AsyncScope 可能会混淆它。 我会像这样重写您的代码:

@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);
           }
        };
    }
}

但实际上,当使用 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();
    }
}

@Test 方法中的代码在虚拟工作流的上下文中执行。这就是为什么,例如,内部测试工作流是使用普通客户端而不是外部客户端创建的。