Skip to main content

Testing

The protoc-gen-go-temporal plugin generates comprehensive testing utilities that integrate seamlessly with Temporal's test framework. These tools enable you to write unit tests, integration tests, and mock-based tests for your workflows, activities, signals, queries, and updates.

Test Client Generation

The plugin generates test clients that mirror the production client interface but operate within Temporal's test environment.

Generated Test Client Interface
// Constructor for test client
func NewTestExampleClient(
env *testsuite.TestWorkflowEnvironment,
workflows ExampleWorkflows,
activities ExampleActivities,
) *TestExampleClient

// All the same methods as production client
func (c *TestExampleClient) CreateFoo(ctx context.Context, req *CreateFooRequest, opts ...*CreateFooOptions) (*CreateFooResponse, error)
func (c *TestExampleClient) CreateFooAsync(ctx context.Context, req *CreateFooRequest, opts ...*CreateFooOptions) (CreateFooRun, error)
func (c *TestExampleClient) GetCreateFoo(ctx context.Context, workflowID, runID string) CreateFooRun

// Signal methods
func (c *TestExampleClient) SetFooProgress(ctx context.Context, workflowID, runID string, req *SetFooProgressRequest) error

// Query methods
func (c *TestExampleClient) GetFooProgress(ctx context.Context, workflowID, runID string) (*GetFooProgressResponse, error)

// Update methods
func (c *TestExampleClient) UpdateFooProgress(ctx context.Context, workflowID, runID string, req *SetFooProgressRequest, opts ...*UpdateFooProgressOptions) (*GetFooProgressResponse, error)

Unit Testing Workflows

Test individual workflows in isolation using the test client and Temporal's test framework.

workflow_test.go
package main

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"go.temporal.io/sdk/testsuite"
"google.golang.org/protobuf/testing/protocmp"

examplev1 "path/to/gen/example/v1"
)

func TestCreateFooWorkflow(t *testing.T) {
var suite testsuite.WorkflowTestSuite
env := suite.NewTestWorkflowEnvironment()

// Create test client with workflow and activity implementations
client := examplev1.NewTestExampleClient(env, &ExampleWorkflows{}, &ExampleActivities{})

ctx := context.Background()

// Execute workflow synchronously
result, err := client.CreateFoo(ctx, &examplev1.CreateFooRequest{
Name: "test-foo",
})

require.NoError(t, err)
require.NotNil(t, result)
require.Empty(t, cmp.Diff(
&examplev1.CreateFooResponse{
Foo: &examplev1.Foo{
Name: "test-foo",
Status: examplev1.Foo_FOO_STATUS_READY,
},
},
result,
protocmp.Transform(),
))
}

Signal and Query Testing

Test workflows that handle signals and/or queries using delayed callbacks for deterministic execution.

signal_test.go
func TestWorkflowWithSignals(t *testing.T) {
var suite testsuite.WorkflowTestSuite
env := suite.NewTestWorkflowEnvironment()
client := examplev1.NewTestExampleClient(env, &ExampleWorkflows{}, &ExampleActivities{})

ctx := context.Background()

// Start workflow asynchronously
run, err := client.CreateFooAsync(ctx, &examplev1.CreateFooRequest{
Name: "signal-test-foo",
})
require.NoError(t, err)

// Send signal using delayed callback for deterministic timing
env.RegisterDelayedCallback(func() {
err := run.SetFooProgress(ctx, &examplev1.SetFooProgressRequest{
Progress: 0.5,
})
require.NoError(t, err)
}, time.Second*5)

// Query workflow state after signal
env.RegisterDelayedCallback(func() {
progress, err := run.GetFooProgress(ctx)
require.NoError(t, err)
require.Equal(t, float32(0.5), progress.GetProgress())
require.Equal(t, examplev1.Foo_FOO_STATUS_CREATING, progress.GetStatus())
}, time.Second*10)

// Send another signal
env.RegisterDelayedCallback(func() {
err := run.SetFooProgress(ctx, &examplev1.SetFooProgressRequest{
Progress: 1.0,
})
require.NoError(t, err)
}, time.Second*20)

// Wait for workflow completion
result, err := run.Get(ctx)
require.NoError(t, err)
require.Equal(t, examplev1.Foo_FOO_STATUS_READY, result.Foo.Status)
}

Update Testing

Test workflow updates with proper staging and result verification.

update_test.go
func TestWorkflowUpdates(t *testing.T) {
var suite testsuite.WorkflowTestSuite
env := suite.NewTestWorkflowEnvironment()
client := examplev1.NewTestExampleClient(env, &ExampleWorkflows{}, &ExampleActivities{})

ctx := context.Background()

run, err := client.CreateFooAsync(ctx, &examplev1.CreateFooRequest{
Name: "update-test-foo",
})
require.NoError(t, err)

// Updates must be executed asynchronously
var updateHandle examplev1.UpdateFooProgressHandle
env.RegisterDelayedCallback(func() {
handle, err := run.UpdateFooProgressAsync(ctx, &examplev1.SetFooProgressRequest{
Progress: 1.0,
})
require.NoError(t, err)
updateHandle = handle
}, time.Second*20)

result, err := run.Get(ctx)
require.NoError(t, err)
require.Equal(t, examplev1.Foo_FOO_STATUS_READY, result.GetFoo().GetStatus())

updateResult, err := updateHandle.Get(ctx)
require.NoError(t, err)
require.Equal(t, float32(1.0), updateResult.GetProgress())
require.Equal(t, examplev1.Foo_FOO_STATUS_READY, updateResult.GetStatus())
}

Activity Mocking

Mock activities to test workflow logic in isolation.

activity_mock_test.go
func TestWorkflowWithMockedActivities(t *testing.T) {
var suite testsuite.WorkflowTestSuite
env := suite.NewTestWorkflowEnvironment()

// Mock activity behavior
env.OnActivity(examplev1.NotifyActivityName, mock.Anything, mock.Anything).Return(nil)
env.OnActivity(examplev1.ProcessDataActivityName, mock.Anything, mock.Anything).Return(
&examplev1.ProcessDataResponse{
ProcessedCount: 42,
Status: "success",
}, nil)

// Create client without activity implementations (using mocks)
client := examplev1.NewTestExampleClient(env, &ExampleWorkflows{}, nil)

ctx := context.Background()

result, err := client.CreateFoo(ctx, &examplev1.CreateFooRequest{
Name: "mocked-test",
})

require.NoError(t, err)
require.Equal(t, "mocked-test", result.Foo.Name)

// Verify that activities were called
env.AssertExpectations(t)
}

Child Workflow Testing

Test workflows that execute child workflows using mocking.

child_workflow_test.go
func TestParentWorkflowWithChildWorkflows(t *testing.T) {
var suite testsuite.WorkflowTestSuite
env := suite.NewTestWorkflowEnvironment()

// Mock child workflow behavior
env.OnWorkflow(examplev1.CreateFooWorkflowName, mock.Anything, mock.Anything).Return(
&examplev1.CreateFooResponse{
Foo: &examplev1.Foo{
Name: "child-foo",
Status: examplev1.Foo_FOO_STATUS_READY,
},
}, nil)

// Register parent workflow
client := examplev1.NewTestExampleClient(env, &ParentWorkflows{}, &ExampleActivities{})

ctx := context.Background()

result, err := client.ExecuteParentWorkflow(ctx, &examplev1.ParentWorkflowRequest{
ChildCount: 3,
})

require.NoError(t, err)
require.Equal(t, int32(3), result.CompletedChildren)

// Verify child workflows were called expected number of times
env.AssertExpectations(t)
}