Skip to main content

Developer's guide - Testing

The Testing section of the Temporal Application development guide describes the frameworks that facilitate Workflow and integration testing.

In the context of Temporal, you can create these types of automated tests:

  • End-to-end: Running a Temporal Server and Worker with all its Workflows and Activities; starting and interacting with Workflows from a Client.
  • Integration: Anything between end-to-end and unit testing.
    • Running Activities with mocked Context and other SDK imports (and usually network requests).
    • Running Workers with mock Activities, and using a Client to start Workflows.
    • Running Workflows with mocked SDK imports.
  • Unit: Running a piece of Workflow or Activity code (a function or method) and mocking any code it calls.

We generally recommend writing the majority of your tests as integration tests.

Because the test server supports skipping time, use the test server for both end-to-end and integration tests with Workers.

Test frameworks

Some SDKs have support or examples for popular test frameworks, runners, or libraries.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Test Activities

An Activity can be tested with a mock Activity environment, which provides a way to mock the Activity context, listen to Heartbeats, and cancel the Activity. This behavior allows you to test the Activity in isolation by calling it directly, without needing to create a Worker to run the Activity.

Run an Activity

If an Activity references its context, you need to mock that context when testing in isolation.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Listen to Heartbeats

When an Activity sends a Heartbeat, be sure that you can see the Heartbeats in your test code so that you can verify them.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Cancel an Activity

If an Activity is supposed to react to a Cancellation, you can test whether it reacts correctly by canceling it.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Test Workflows

Mock Activities

Mock the Activity invocation when unit testing your Workflows.

When integration testing Workflows with a Worker, you can mock Activities by providing mock Activity implementations to the Worker.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Skip time

Some long-running Workflows can persist for months or even years. Implementing the test framework allows your Workflow code to skip time and complete your tests in seconds rather than the Workflow's specified amount.

For example, if you have a Workflow sleep for a day, or have an Activity failure with a long retry interval, you don't need to wait the entire length of the sleep period to test whether the sleep function works. Instead, test the logic that happens after the sleep by skipping forward in time and complete your tests in a timely manner.

note

Skipping time is not relevant to unit testing Workflow code, because in that case you’re mocking functions that take time, like sleep and Activity calls.

The test framework included in most SDKs is an in-memory implementation of Temporal Server that supports skipping time. Time is a global property of an instance of TestWorkflowEnvironment: skipping time (either 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, you could run all tests with automatic time skipping in parallel, and then all tests with manual time skipping in series, and then all tests without time skipping in parallel.

Setting up

Learn to set up the time-skipping test framework in the SDK of your choice.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Automatic method

You can skip time automatically in the SDK of your choice. Start a test server process that skips time as needed. For example, in the time-skipping mode, Timers, which include sleeps and conditional timeouts, are fast-forwarded except when Activities are running.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Manual method

Learn to skip time manually in the SDK of your choice.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Skip time in Activities

Learn to skip time in Activities in the SDK of your choice.

Content is planned but not yet available.

The information you are looking for may be found in the legacy docs.

Workflow context

For a function or method to run in the Workflow context (where it’s possible to get the current Workflow info, or running inside the sandbox in the case of TypeScript or Python), it needs to be run by the Worker as if it were a Workflow.

note

This section is applicable in Python and TypeScript. In Python, we allow testing of Workflows only and not generic Workflow-related code.

Not applicable to this SDK.

Assert in Workflow

The assert statement is a convenient way to insert debugging assertions into the Workflow context.

The assert method is available in Python and TypeScript.

Not applicable to this SDK.

Replay

Replay recreates the exact state of a Workflow Execution. You can replay a Workflow from the beginning of its Event History.

Replay succeeds only if the Workflow DefinitionLink preview iconWhat is a Workflow Definition?

A Workflow Definition is the code that defines the constraints of a Workflow Execution.

Learn more is compatible with the provided history from a deterministic point of view.

When you test changes to your Workflow Definitions, we recommend doing the following as part of your CI checks:

  1. Determine which Workflow Types or Task Queues (or both) will be targeted by the Worker code under test.
  2. Download the Event Histories of a representative set of recent open and closed Workflows from each Task Queue, either programmatically using the SDK client or via tctl.
  3. Run the Event Histories through replay.
  4. Fail CI if any error is encountered during replay.

The following are examples of fetching and replaying Event Histories:

Use the worker.WorkflowReplayer to replay an existing Workflow Execution from its Event History to replicate errors.

For example, the following code retrieves the Event History of a Workflow:

import (
"context"

"go.temporal.io/api/enums/v1"
"go.temporal.io/api/history/v1"
"go.temporal.io/sdk/client"
)

func GetWorkflowHistory(ctx context.Context, client client.Client, id, runID string) (*history.History, error) {
var hist history.History
iter := client.GetWorkflowHistory(ctx, id, runID, false, enums.HISTORY_EVENT_FILTER_TYPE_ALL_EVENT)
for iter.HasNext() {
event, err := iter.Next()
if err != nil {
return nil, err
}
hist.Events = append(hist.Events, event)
}
return &hist, nil
}

This history can then be used to replay. For example, the following code creates a WorkflowReplayer and register the YourWorkflow Workflow function. Then it calls the ReplayWorkflowHistory to replay the Event History and return an error code.

import (
"context"

"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
)

func ReplayWorkflow(ctx context.Context, client client.Client, id, runID string) error {
hist, err := GetWorkflowHistory(ctx, client, id, runID)
if err != nil {
return err
}
replayer := worker.NewWorkflowReplayer()
replayer.RegisterWorkflow(YourWorkflow)
return replayer.ReplayWorkflowHistory(nil, hist)
}

The code above will cause the Worker to re-execute the Workflow's Workflow Function using the original Event History. If a noticeably different code path was followed or some code caused a deadlock, it will be returned in the error code. Replaying a Workflow Execution locally is a good way to see exactly what code path was taken for given input and events.

You can replay many Event Histories by registering all the needed Workflow implementation and then calling ReplayWorkflowHistory repeatedly.