Skip to main content

Testing

TestWorkflowEnvironment runs workflow code in-memory without a Cadence server. It executes workflow and activity logic deterministically, mocks activities with fixed values or custom functions, and advances virtual time for timer-based workflows.

Basic test

import pytest
from cadence import Registry, workflow
from cadence.workflow import execute_activity
from cadence.testing import TestWorkflowEnvironment
from datetime import timedelta

registry = Registry()

@registry.workflow()
class GreetingWorkflow:
@workflow.run
async def run(self, name: str) -> str:
return await execute_activity(
"greet",
str,
name,
start_to_close_timeout=timedelta(seconds=5),
)

@pytest.mark.asyncio
async def test_greeting():
env = TestWorkflowEnvironment(registry)
env.on_activity("greet", result="Hello, World!")

client = env.client
await client.start_workflow(
"GreetingWorkflow",
"World",
workflow_id="test-greeting",
task_list="tl",
execution_start_to_close_timeout=timedelta(minutes=1),
)

result = env.get_workflow_result(str, workflow_id="test-greeting")
assert result == "Hello, World!"

Mocking activities

Mock an activity by name with a fixed return value:

env.on_activity("fetch_order", result={"id": "123", "status": "pending"})

Mock with a function to inspect arguments or return dynamic values:

def fake_fetch(order_id: str) -> dict:
assert order_id == "123"
return {"id": order_id, "status": "pending"}

env.on_activity("fetch_order", fn=fake_fetch)

The mock function receives the decoded activity arguments. It can be sync or async.

Checking workflow results

result = env.get_workflow_result(str, workflow_id="my-wf")

If the workflow failed, get_workflow_result re-raises the error. To inspect the error without re-raising:

error = env.get_workflow_error(workflow_id="my-wf")

Check whether a workflow has finished:

assert env.is_workflow_completed(workflow_id="my-wf")

Testing signals

Send a signal from the test after starting the workflow:

@pytest.mark.asyncio
async def test_approval():
env = TestWorkflowEnvironment(registry)
client = env.client

execution = await client.start_workflow(
"ApprovalWorkflow",
workflow_id="approval-test",
task_list="tl",
execution_start_to_close_timeout=timedelta(minutes=1),
)

await client.signal_workflow(execution.workflow_id, "", "approve", True)

result = env.get_workflow_result(bool, workflow_id="approval-test")
assert result is True

Testing queries

await client.signal_workflow("my-wf", "", "set_status", "processing")
status = await client.query_workflow("my-wf", "", "get_status", result_type=str)
assert status == "processing"

TestWorkflowEnvironment reference

Method / PropertyDescription
env.clientClient-compatible object for starting and interacting with workflows
env.on_activity(name, result=...)Mock an activity with a fixed return value
env.on_activity(name, fn=...)Mock an activity with a callable
env.get_workflow_result(type, workflow_id="")Get the decoded result; raises if the workflow failed
env.get_workflow_error(workflow_id="")Get the error if the workflow failed, or None
env.is_workflow_completed(workflow_id="")Whether the workflow has finished
env.now()Current virtual time
env.close()Shut down the executor

TestWorkflowEnvironment is also a synchronous context manager:

with TestWorkflowEnvironment(registry) as env:
...