Go QueryWorkflow method for testing queries
Use the QueryWorkflow() method on TestWorkflowEnvironment to query the state of a running Workflow. Query the Workflow either after ExecuteWorkflow() is done or within a RegisterDelayedCallback() callback, otherwise a runtime error panic will occur.
Go workflow query example with SetQueryHandler
Use workflow.SetQueryHandler(ctx, "queryName", func(input []byte) (interface{}, error) { return value, nil }) to register a query handler in a Workflow. The query handler receives input as bytes and returns the query result.
Go RegisterDelayedCallback for time control
Use env.RegisterDelayedCallback(callback, duration) to register a callback that fires after a specified duration in mock time. This does not make the test wait in real time; Temporal's test framework advances time internally. This is useful for sending signals or querying workflows at specific times.
Go Activity mocking with OnActivity
Mock an Activity using s.env.OnActivity(ActivityFunction, mock.Anything, mock.Anything).Return(value, error). This prevents the actual Activity code from executing and returns the specified value or error instead.
Go Activity override with custom implementation
Override an Activity with a custom implementation by passing a function to Return(): s.env.OnActivity(ActivityFunction, mock.Anything, mock.Anything).Return(func(ctx context.Context, params...) (result, error) { ... }). The framework validates that the function signature matches the original Activity.
Go mock Nexus synchronous operation
Mock a synchronous Nexus operation using s.env.OnNexusOperation("service-name", nexus.NewOperationReference[InputType, OutputType]("operation-name"), inputValue, workflowNexusOperationOptions).Return(&nexus.HandlerStartOperationResultSync[OutputType]{Value: outputValue}, error). Use After(duration) to add a delay before returning values.
Go mock Nexus asynchronous operation
Mock an asynchronous Nexus operation by returning &nexus.HandlerStartOperationResultAsync{OperationToken: "token-string"}. Then call env.RegisterNexusAsyncOperationCompletion("service-name", "operation-name", "operation-token", outputValue, error, delay) to register the completion result for that operation token.
Go override Nexus synchronous operation with custom logic
Override a Nexus synchronous operation by creating the operation with nexus.NewSyncOperation("operation-name", func(ctx context.Context, input InputType, options nexus.StartOperationOptions) (OutputType, error) { ... }), registering it in a service with service.Register(operation), and registering the service with env.RegisterNexusService(service).
Go override Nexus asynchronous operation with workflow
Override a Nexus asynchronous operation by creating it with nexus.NewWorkflowRunOperation("operation-name", handlerWorkflowFunction, func(ctx context.Context, input InputType, options nexus.StartOperationOptions) (client.StartWorkflowOptions, error) { ... }). Register it in a service and register the service with env.RegisterNexusService(service).
Go automatic time skipping in test environment
The Go SDK test environment automatically skips time when using testsuite.TestWorkflowEnvironment. Time advances automatically whenever there are no Activities running: Workflow timers like workflow.Sleep are fast-forwarded, but time does not skip while Activities are executing.
Go replay multiple workflow histories
To replay many Event Histories, register all needed Workflow implementations with the same WorkflowReplayer instance, then call ReplayWorkflowHistory() repeatedly for each history.
Go RegisterDelayedCallback with Signal-With-Start
When using Signal-With-Start with RegisterDelayedCallback, set the delay to 0.
Go Activity execution without mocking runs actual code
Unless Activity invocations are mocked or Activity implementation replaced, the test environment will execute the actual Activity code including any calls to outside services when running ExecuteWorkflow().
Go query workflow timing requirement
Query a Workflow in tests only after ExecuteWorkflow() is done or within a RegisterDelayedCallback() callback. Querying at other times will cause a runtime error panic.
Go RegisterDelayedCallback does not cause real time waits
RegisterDelayedCallback() does not make tests wait in real time. Temporal's test framework advances time internally, so tests complete quickly even with large time delays like 90 days.
Go test time behavior isolation
Time is a global property of a TestWorkflowEnvironment instance. Skipping time applies to all currently running tests. If different tests need different time behaviors, run tests in series or with separate TestWorkflowEnvironment instances. For example, run all tests with automatic time skipping in parallel, then all tests with manual time skipping in series.
Java SDK Testing - Three types of automated tests
In Temporal, you can create three types of automated tests: End-to-end tests (running a Temporal Server and Worker with all Workflows, Activities, and Nexus Operations; starting and interacting with Workflows from a Client); Integration tests (anything between end-to-end and unit testing, including running Activities with mocked Context and SDK imports, running Workers with mock Activities and Nexus Operations, or running Workflows with mocked SDK imports); Unit tests (running a piece of Workflow, Activity, or Nexus Operation code and mocking any code it calls). The majority of tests should generally be written as integration tests.
Java SDK TestWorkflowEnvironment - in-memory Temporal service with time skipping
The Temporal Java SDK 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. The test framework supports skipping time for both end-to-end and integration tests with Workers.
Java SDK temporal-testing dependency setup
To use the Java SDK test framework, add io.temporal:temporal-testing as a test dependency. For Maven: add a dependency with groupId io.temporal, artifactId temporal-testing, version 1.36.0, scope test. For Gradle Groovy DSL: testImplementation("io.temporal:temporal-testing:1.36.0"). For JUnit4 extensions, require capability io.temporal:temporal-testing-junit4. For JUnit5 extensions, require capability io.temporal:temporal-testing-junit5. The version should match your Temporal Java SDK version.
Java SDK TestActivityEnvironment - testing Activities
Temporal provides TestActivityEnvironment and TestActivityExtension classes for testing Activities outside the scope of a Workflow. Activities can be tested in isolation by calling them directly without creating a Worker. TestActivityEnvironment allows you to test for exceptions thrown during Activity invocation, exceptions when checking for results, and verify Activity return values.
Java SDK run Activity test example
To run an Activity test with TestActivityEnvironment: create a TestActivityEnvironment instance, register the Activity implementations with registerActivitiesImplementations(), create an Activity stub with newActivityStub(), invoke the Activity method and assert on the result.
Java SDK Activity Heartbeat testing with setActivityHeartbeatListener
To listen to Heartbeats in Activity tests, use TestActivityEnvironment.setActivityHeartbeatListener() with a callback that receives heartbeats. The example shows using AtomicInteger to count heartbeats: env.setActivityHeartbeatListener(Void.class, heartbeat -> heartbeatCount.incrementAndGet()).
Java SDK Activity cancellation testing with TestWorkflowEnvironment
To test Activity cancellation, use TestWorkflowEnvironment with a Worker that registers both the Workflow and Activity implementations. Start the Workflow with WorkflowClient.start(), register a delayed callback to send a cancellation signal after a duration (e.g., env.registerDelayedCallback(Duration.ofSeconds(1), () -> WorkflowStub.fromTyped(workflow).signal("cancelActivity"))), then catch the WorkflowFailedException which should contain an ActivityFailure with a CanceledFailure cause.
Java SDK mock Activities in Workflow tests
When integration testing Workflows with a Worker, you can mock Activities by providing mock Activity implementations to the Worker. For unit tests where you do not wish to execute actual Activity or Nexus Operation implementations, you can use a framework such as Mockito to mock them.
Java SDK TestWorkflowRule for JUnit4
For JUnit4 tests, Temporal provides the TestWorkflowRule class which simplifies the Temporal test environment setup and the creation and shutdown of Workflow Workers. Use @Rule public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder().setWorkflowTypes(...).setActivityImplementations(...).build(). Then use testWorkflowRule.getWorkflowClient() and testWorkflowRule.getTaskQueue() in tests.
Java SDK TestWorkflowExtension for JUnit5
For JUnit5 tests, Temporal provides the TestWorkflowExtension helper class for simplifying the test environment setup and Workflow Worker startup and shutdown. Use @RegisterExtension public static final TestWorkflowExtension testWorkflowExtension = TestWorkflowExtension.newBuilder().setWorkflowTypes(...).setActivityImplementations(...).build(). Test methods receive TestWorkflowEnvironment testEnv, Worker worker, and workflow stub parameters injected as arguments.
Java SDK mock Nexus Operations in Workflow tests
When integration testing Workflows with a Worker, you can mock Nexus operations by providing mock Nexus Service handlers to the Worker. For JUnit4, use TestWorkflowRule.setNexusServiceImplementation(). For JUnit5, use TestWorkflowExtension.setNexusServiceImplementation(). You can also mock the Nexus service itself using Mockito instead of mocking individual handlers.
Java SDK Nexus mock handler example with JUnit5
Example of mocking Nexus handlers with JUnit5: Create a TestWorkflowExtension with setNexusServiceImplementation(new SampleNexusServiceImpl()) and registerWorkflowImplementationTypes(HelloCallerWorkflowImpl.class). In the test method, call worker.registerWorkflowImplementationFactory(HelloHandlerWorkflow.class, () -> { ... }) to register a mocked handler. Test method receives TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow as parameters.
Java SDK mock Nexus Service implementation with JUnit5
To mock the Nexus service itself with JUnit5: Create a mock instance of the Nexus service class. Create a test-only Nexus service implementation class annotated with @ServiceImpl(service = SampleNexusService.class) that delegates to the Mockito mock. Implement operation handlers with @OperationImpl that use OperationHandler.sync() to return results inline. Pass this test implementation to TestWorkflowExtension.setNexusServiceImplementation().
Java SDK automatic time skipping in Workflow tests
When you execute a Workflow and wait for the result in a test, the test environment automatically skips Workflow timers such as Workflow.sleep(). This means Workflow timers are fast-forwarded. Time does not skip while Activities and Nexus operations are executing. Nexus operation handlers timeout after 10 seconds and time skipping is allowed while waiting for retries.
Java SDK automatic time skipping example
Example of automatic time skipping: A Workflow that calls Workflow.sleep(Duration.ofDays(1)) will complete immediately in TestWorkflowEnvironment because Workflow time is automatically advanced. Write the test using TestWorkflowEnvironment, create a Worker with registerWorkflowImplementationTypes(), register Activity implementations, start the environment, create a Workflow stub, execute the Workflow, and assert on the result. The sleep completes without waiting one day.
Java SDK Workflow.sleep vs Thread.sleep in tests
Use Workflow.sleep() in Workflow code, not Thread.sleep(). Workflow.sleep() creates a Temporal timer that the test environment can skip. Thread.sleep() blocks a Java thread in real time and is not controlled by Temporal's time-skipping test server.
Java SDK manual time skipping with TestWorkflowEnvironment.sleep()
Use TestWorkflowEnvironment.sleep(Duration) when you want to advance virtual time yourself and inspect intermediate Workflow state. Start the Workflow asynchronously with WorkflowClient.start(), then call testEnv.sleep() from the test to advance time and check intermediate state using Query methods.
Java SDK manual time skipping example with queries
Example of manual time skipping: Start Workflow with WorkflowClient.start(workflow::run). Query the Workflow state with workflow.queryMethod() to verify initial state. Call testEnv.sleep(Duration.ofHours(25)) to advance time. Query again to verify state changed. Repeat as needed. The Workflow must have @QueryMethod methods to retrieve intermediate state.
Java SDK time skipping configuration - parallel vs series
Time is a global property of a TestWorkflowEnvironment instance. Skipping time (automatically or manually) applies to all currently running tests. If you need different time behaviors for different tests, run your tests in a series or with separate instances of the test server. For example, run all tests with automatic time skipping in parallel, then all tests with manual time skipping in series, then all tests without time skipping in parallel.
Java SDK Workflow replay with WorkflowReplayer
To replay Workflow Executions, use the WorkflowReplayer class in the temporal-testing package. Replay recreates the exact state of a Workflow Execution and succeeds only if the Workflow Definition is compatible with the provided history from a deterministic point of view. Use WorkflowReplayer.replayWorkflowExecutions(histories, failFast, WorkflowClass1.class, WorkflowClass2.class) or WorkflowReplayer.replayWorkflowExecution(file, WorkflowClass.class) to replay from a file.
Java SDK replay Event Histories from server
To replay Workflow Executions from the server: Use ListWorkflowExecutionsRequest with a query to filter workflows (e.g., "TaskQueue = 'mytaskqueue'"). Get the ListWorkflowExecutionsResponse from the service stub's blockingStub().listWorkflowExecutions(). For each workflow execution info, fetch the history using GetWorkflowExecutionHistoryRequest with the namespace and execution. Create WorkflowExecutionHistory objects from the histories. Pass to WorkflowReplayer.replayWorkflowExecutions(). This requires Advanced Visibility to be enabled.
Java SDK replay Event Histories from JSON file
To replay Workflow Executions from a JSON file: Load the file with new File("my_history.json"). Call WorkflowReplayer.replayWorkflowExecution(file, MyWorkflow.class). If Event History is non-deterministic, an error is thrown.
Java SDK replay testing CI checks recommendation
When testing changes to Workflow Definitions, do the following as part of CI checks: (1) Determine which Workflow Types or Task Queues will be targeted by the Worker code under test; (2) Download Event Histories of a representative set of recent open and closed Workflows from each Task Queue, either programmatically using the SDK client or via Temporal CLI; (3) Run the Event Histories through replay; (4) Fail CI if any error is encountered during replay.
Java SDK WorkflowReplayer failFast parameter
WorkflowReplayer.replayWorkflowExecutions() accepts a failFast boolean argument. When failFast is true, the replay fails immediately on first error. When failFast is false, the replay waits until all histories have been replayed before reporting results.