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)
}