【问题标题】:Unit testing SWF with @Asynchronous methods使用 @Asynchronous 方法对 SWF 进行单元测试
【发布时间】:2016-06-27 11:27:25
【问题描述】:

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

@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 方法调用,工作流似乎冻结了。

【问题讨论】:

    标签: java unit-testing amazon-web-services amazon-swf


    【解决方案1】:

    我认为问题在于您同时使用了 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 方法中的代码在虚拟工作流的上下文中执行。这就是为什么,例如,内部测试工作流是使用普通客户端而不是外部客户端创建的。

    【讨论】:

    • 在使用 FlowBlockJUnit4ClassRunner 运行时,有没有办法获得与 getAsynchronousThreadDumpAsString 等效的东西?我已经注入了异常,但它没有抛出,我猜它卡在某个地方。
    • 是的,只需指定测试的超时时间:@Test(expected=RuntimeException.class, timeout=1000)
    • 超时显示线程转储,但它似乎仍然存在原始问题,活动由于某种原因没有抛出异常,并且异步方法正在等待结果。尝试一种不同的方法,我模拟了一个没有输入异步块的活动方法,它抛出了 NullPointerException - com.amazonaws.services.simpleworkflow.flow.junit.WorkflowTestStatement$2$1.doTry(WorkflowTestStatement.java:108) - 我甚至删除了对工作流的调用,并且它仍然具有仅来自检测模拟的 NPE。会不会是配置问题?
    • 能不能试试不使用mock框架,直接实现Activity接口?
    • 成功了,谢谢!奇怪的是,在我直接实现了活动接口之后,我能够监视该对象(以验证活动是否按预期被调用等)并且它工作得很好。
    猜你喜欢
    • 2012-06-01
    • 1970-01-01
    • 2021-09-16
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    相关资源
    最近更新 更多