2

I have a parent workflow (ParentWorkflow) calling a child workflow (ChildWorkflow) and I'm trying to test out the call.

The parent code looks something like this:

public class ParentWorkflow {
    private final ChildWorkflowClientFactory childWorkflowClientFactory =
            new ChildWorkflowClientFactoryImpl();

    public void runWorkflow() {
        new TryCatch() {
            @Override
            protected void doTry() throws Throwable {
                Promise<Void> workflowFinished = childWorkflowClient.childWorkflow(x);
                ...
            }
        ...
    }
}

I want to mock out the childWorkflowClient.childWorkflow(x) call, however when I am hooking up the unit test I don't appear to have the option to inject the client factory, the unit test code looks like this:

@Rule
public WorkflowTest workflowTest = new WorkflowTest();
@Mock
private Activities mockActivities;

private ParentWorkflowClientFactory workflowFactory
        = new ParentWorkflowClientFactoryImpl();

@Before
public void setUp() throws Exception {
    // set up mocks
    initMocks(this);

    workflowTest.addActivitiesImplementation(mockActivities);
    workflowTest.addWorkflowImplementationType(ParentWorkflowImpl.class);
    workflowTest.addWorkflowImplementationType(ChildWorkflowImpl.class);

I don't appear to be able to pass anything into the workflow implementation classes, is there another way I can mock the child workflow out?

Allan5
  • 351
  • 5
  • 17

2 Answers2

7

You can test workflow code directly mocking its dependencies without using workflowTest:

/**
 * Rule is still needed to initialize asynchronous framework.
 */
@Rule
public WorkflowTest workflowTest = new WorkflowTest();
@Mock
private ActivitiesClient mockActivities;
@Mock
private BWorkflowClientFactory workflowFactory;


@Before
public void setUp() throws Exception {
  // set up mocks
  initMocks(this);
}

@Test
public void myTest() {
  AWorkflowImpl w = new AWorkflowImpl(workflowFactory);
  w.execute(); // whatever execute method of the workflow
}

This approach allows testing parts of the workflow encapsulated in other objects instead of the entire workflow.

If for whatever reason (for example you are using other testing framework than JUnit) you don't want to rely on WorkflowTest @Rule asynchronous code can be always executed using AsyncScope:

@Test
public void asyncTest() {
   AsyncScope scope = new AsyncScope() {
      protected void doAsync() {
         // Any asynchronous code
         AWorkflowImpl w = new AWorkflowImpl(workflowFactory);
         w.execute(); // whatever execute method of the workflow
      }
   };
   scope.eventLoop();
}
Maxim Fateev
  • 6,458
  • 3
  • 20
  • 35
  • Thanks for the response! This came very close to working but the code I want to test in the parent workflow is surrounded by a TryCatch block and it doesn't seem to get executed. Any ideas how to trigger code in there? I suppose I could just bring it out to a separate code block and test that one, but would be nice if I could test it in it's original context directly. – Allan5 May 28 '15 at 17:35
  • The best way to find out where the asynchronous code is "stuck" is to use AsyncScope.getAsynchronousThreadDumpAsString method. It will show "asynchronous stack dump" which lists "asynchronous stack trace" for every outstanding task. Without looking at the code it is hard to give more concrete answer. – Maxim Fateev May 28 '15 at 18:32
  • BTW uf you are using WorkflowTest and specify timeout for the test then the "async thread dump" is emitted automatically. – Maxim Fateev May 28 '15 at 18:44
  • Have updated code above to show what is happening, but after a bit more tweaking found that the AsyncScope you suggested above solves the problem, thanks for the help. – Allan5 May 28 '15 at 21:36
0

EDIT: The below only applies to SpringWorkflowTest; WorkflowTest doesn't have addWorkflowImplementation for some reason.

The correct way to use the WorkflowTest would be to add a mock implementation for the child workflow rather than adding the actual type:

@Rule
public SpringWorkflowTest workflowTest = new SpringWorkflowTest();
@Mock
private Activities mockActivities;
@Mock
private ChildWorkflow childWorkflowMock;

private ParentWorkflowClientFactory workflowFactory
        = new ParentWorkflowClientFactoryImpl();

@Before
public void setUp() throws Exception {
    // set up mocks
    initMocks(this);

    workflowTest.addActivitiesImplementation(mockActivities);
    workflowTest.addWorkflowImplementationType(ParentWorkflowImpl.class);
    workflowTest.addWorkflowImplementation(childWorkflowMock);
    ...
}

The framework will then call this mock instead of the actual implementation when you use the factory.

stickyShift
  • 13
  • 2
  • 5
  • What version of the SDK are you using? There is no such `addWorkflowImplementation` method for `WorkflowTest`. – jayjyli Jul 17 '18 at 22:28
  • My bad - I was looking at SpringWorkflowTest, which does have `addWorkflowImplementation`: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/junit/spring/SpringWorkflowTest.html – stickyShift Jul 18 '18 at 19:46
  • Oh got it, sorry I didn't see you were using Spring in your snippet. – jayjyli Jul 19 '18 at 19:28