Skip to main content
Version: june-2022

Testing and Debugging

Overview

The Temporal Java SDK provides a test framework to facilitate Workflow unit and integration testing. The test framework provides a TestWorkflowEnvironment class which includes an in-memory implementation of the Temporal service that supports automatic time skipping. This allows you to easily test long-running Workflows in seconds, without having to change your Workflow code.

You can use the provided TestWorkflowEnvironment with a Java unit testing framework of your choice, such as JUnit.

Setup testing dependency

To start using the Java SDK test framework, you need to add io.temporal:temporal-testing as a dependency to your project:

Apache Maven:

<dependency>
<groupId>io.temporal</groupId>
<artifactId>temporal-testing</artifactId>
<version>1.11.0</version>
<scope>test</scope>
</dependency>

Gradle Groovy DSL:

testImplementation ("io.temporal:temporal-testing:1.11.0")

Make sure to set the version that matches your dependency version of the Temporal Java SDK.

Sample unit tests

The following code implements unit tests for the HelloActivity sample:

public class HelloActivityTest {

private TestWorkflowEnvironment testEnv;
private Worker worker;
private WorkflowClient client;

// Set up the test workflow environment
@Before
public void setUp() {
testEnv = TestWorkflowEnvironment.newInstance();
worker = testEnv.newWorker(TASK_QUEUE);
// Register your workflow implementations
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);

client = testEnv.getWorkflowClient();
}

// Clean up test environment after tests are completed
@After
public void tearDown() {
testEnv.close();
}

@Test
public void testActivityImpl() {
// This uses the actual activity impl
worker.registerActivitiesImplementations(new GreetingActivitiesImpl());

// Start test environment
testEnv.start();

// Create the workflow stub
GreetingWorkflow workflow =
client.newWorkflowStub(
GreetingWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build());

// Execute our workflow waiting for it to complete
String greeting = workflow.getGreeting("World");
assertEquals("Hello World!", greeting);
}
}

In cases where you do not wish to execute your actual Activity implementations during unit testing, you can use a framework such as Mockito to mock them.

The following code implements a unit test for the HelloActivity sample which shows how activities can be mocked:

public class HelloActivityTest {

private TestWorkflowEnvironment testEnv;
private Worker worker;
private WorkflowClient client;

// Set up the test workflow environment
@Before
public void setUp() {
testEnv = TestWorkflowEnvironment.newInstance();
worker = testEnv.newWorker(TASK_QUEUE);
// Register your workflow implementations
worker.registerWorkflowImplementationTypes(GreetingWorkflowImpl.class);

client = testEnv.getWorkflowClient();
}

// Clean up test environment after tests are completed
@After
public void tearDown() {
testEnv.close();
}

@Test
public void testMockedActivity() {
// Mock our workflow activity
GreetingActivities activities = mock(GreetingActivities.class);
when(activities.composeGreeting("Hello", "World")).thenReturn("Hello Mocked World!");
worker.registerActivitiesImplementations(activities);

// Start test environment
testEnv.start();

// Create the workflow stub
GreetingWorkflow workflow =
client.newWorkflowStub(
GreetingWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue(TASK_QUEUE).build());

// Execute our workflow waiting for it to complete
String greeting = workflow.getGreeting("World");
assertEquals("Hello Mocked World!", greeting);
}
}

Testing with JUnit4

For Junit4 tests, Temporal provides the TestWorkflowRule class which simplifies the Temporal test environment setup, as well as the creation and shutdown of Workflow Workers in your tests.

Make sure to set the version that matches your dependency version of the Temporal Java SDK.

We can now rewrite our above mentioned "HelloActivityTest" test class as follows:

public class HelloActivityJUnit4Test {
@Rule
public TestWorkflowRule testWorkflowRule =
TestWorkflowRule.newBuilder()
.setWorkflowTypes(GreetingWorkflowImpl.class)
.setActivityImplementations(new GreetingActivitiesImpl())
.build();

@Test
public void testActivityImpl() {
// Get a workflow stub using the same task queue the worker uses.
GreetingWorkflow workflow =
testWorkflowRule
.getWorkflowClient()
.newWorkflowStub(
GreetingWorkflow.class,
WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build());
// Execute a workflow waiting for it to complete.
String greeting = workflow.getGreeting("World");
assertEquals("Hello World!", greeting);

testWorkflowRule.getTestEnvironment().shutdown();
}
}

Testing with JUnit5

For Junit5 tests, Temporal also provides the TestWorkflowExtension helped class which can be used to simplify the Temporal test environment setup as well as Workflow Worker startup and shutdowns.

To start using JUnit5 TestWorkflowExtension in your tests with Gradle, you need to enable capability [io.temporal:temporal-testing-junit5]:

Make sure to set the version that matches your dependency version of the Temporal Java SDK.

We can now use JUnit5 and rewrite our above mentioned "HelloActivityTest" test class as follows:

public class HelloActivityJUnit5Test {
@RegisterExtension
public static final TestWorkflowExtension testWorkflowExtension =
TestWorkflowExtension.newBuilder()
.setWorkflowTypes(GreetingWorkflowImpl.class)
.setActivityImplementations(new GreetingActivitiesImpl())
.build();

@Test
public void testActivityImpl(
TestWorkflowEnvironment testEnv, Worker worker, GreetingWorkflow workflow) {
// Execute a workflow waiting for it to complete.
String greeting = workflow.getGreeting("World");
assertEquals("Hello World!", greeting);
}
}

You can find all unit tests for the Temporal Java samples repository in its test package.

Debugging

In addition to writing unit and integration tests, debugging your Workflows is also a very valuable testing tool. You can debug your Workflow code using a debugger provided by your favorite Java IDE.

Note that when debugging your Workflow code, the Temporal Java SDK includes deadlock detection which fails a Workflow Task in case the code blocks over a second without relinquishing execution control. Because of this you can often encounter the PotentialDeadlockException Exception while stepping through Workflow code during debugging.

To alleviate this issue, you can set the TEMPORAL_DEBUG environment variable to true before debugging your Workflow code. Make sure to set TEMPORAL_DEBUG to true only during debugging.