Testing API Reference¶
Reference for the test runners, the test result, operation accessors, and the enums used across the testing SDKs. For an onboarding walkthrough, start with Authoring.
LocalDurableTestRunner¶
Runs a durable handler in-process against an in-memory checkpoint store. No AWS credentials, no deployment, and no containers are required. Use it for unit tests and CI.
Create a runner¶
Call LocalDurableTestRunner.setupTestEnvironment() in beforeAll and
LocalDurableTestRunner.teardownTestEnvironment() in afterAll.
static setupTestEnvironment(params?: LocalDurableTestRunnerSetupParameters): Promise<void>
static teardownTestEnvironment(): Promise<void>
Constructor parameters:
handlerFunction(required) The handler created withwithDurableExecution.
Use as a context manager. The context manager starts the scheduler thread on entry and stops it on exit.
Parameters:
handler(required) The handler decorated with@durable_execution.poll_interval(optional) Seconds between internal polling cycles. Defaults to1.0.
// Class-based input type
LocalDurableTestRunner.create(Class<I> inputType, BiFunction<I, DurableContext, O> handlerFn)
// TypeToken-based input type (for generic types)
LocalDurableTestRunner.create(TypeToken<I> inputType, BiFunction<I, DurableContext, O> handlerFn)
// With a custom DurableConfig
LocalDurableTestRunner.create(Class<I> inputType, BiFunction<I, DurableContext, O> handlerFn, DurableConfig config)
// From a DurableHandler instance (extracts config automatically)
LocalDurableTestRunner.create(Class<I> inputType, DurableHandler<I, O> handler)
Override config or the output type on an existing runner:
LocalDurableTestRunner<I, O> withDurableConfig(DurableConfig config)
LocalDurableTestRunner<I, O> withOutputType(Class<O> outputType)
LocalDurableTestRunner<I, O> withOutputType(TypeToken<O> outputType)
Parameters:
inputType(required) The input type class orTypeToken.handlerFn(required) ABiFunction<I, DurableContext, O>implementing the handler logic.config(optional) ADurableConfig. The runner overrides theDurableExecutionClientwith its in-memory implementation but preserves all other settings such as customSerDes.handler(optional) ADurableHandlerinstance. The runner extracts its configuration automatically.
The local runner type is DurableTestRunner<TInput, TOutput>. Construct it with the
workflow delegate and dispose it with await using:
DurableTestRunner(
Func<TInput, IDurableContext, Task<TOutput>> handler,
TestRunnerOptions? options = null)
await using var runner = new DurableTestRunner<object?, string>(
Workflow,
new TestRunnerOptions { SkipTime = true });
There is no static setup/teardown. The await using declaration and DisposeAsync()
replace the TypeScript setupTestEnvironment/teardownTestEnvironment lifecycle.
Constructor parameters:
handler(required) AFunc<TInput, IDurableContext, Task<TOutput>>, either a method group or an inline(input, ctx) => ...async lambda.options(optional) ATestRunnerOptionsrecord. Defaults to a new instance withSkipTime = true.
Run the handler¶
run() drives the full replay loop until the execution completes or fails.
Parameters:
params(optional) AnInvokeRequestobject.payload(optional) The input payload to pass to the handler.
Returns: Promise<TestResult>
run(
input: str | None = None,
timeout: int = 900,
function_name: str = "test-function",
execution_name: str = "execution-name",
account_id: str = "123456789012",
) -> DurableFunctionTestResult
Parameters:
input(optional) JSON-encoded input string. Defaults toNone.timeout(optional) Maximum seconds to wait for completion. Defaults to900.function_name(optional) Function name used internally. Defaults to"test-function".execution_name(optional) Execution name used internally. Defaults to"execution-name".account_id(optional) Account ID used internally. Defaults to"123456789012".
Returns: DurableFunctionTestResult
Raises: TimeoutError if the execution does not complete within timeout.
// Runs a single invocation (may return PENDING)
TestResult<O> run(I input)
// Drives the full replay loop until SUCCEEDED, FAILED, or PENDING with no
// auto-advanceable operations
TestResult<O> runUntilComplete(I input)
Parameters:
input(required) The handler input.
Returns: TestResult<O>
Task<TestResult<TOutput>> RunAsync(
TInput input,
TimeSpan? timeout = null,
CancellationToken cancellationToken = default)
RunAsync drives the full replay loop until the workflow reaches a terminal state. It
throws InvalidOperationException if the workflow suspends on a callback. Use the
StartAsync + WaitForCallbackAsync two-call pattern for callback workflows.
Parameters:
input(required) The handler input.timeout(optional) Wall-clock timeout for the call. Defaults toTestRunnerOptions.DefaultTimeout(30 seconds).cancellationToken(optional) ACancellationToken.
Returns: Task<TestResult<TOutput>>
Run asynchronously¶
Not applicable. run() already drives the full replay loop.
# Start execution without waiting for completion
run_async(
input: str | None = None,
timeout: int = 900,
function_name: str = "test-function",
execution_name: str = "execution-name",
account_id: str = "123456789012",
) -> str # returns execution_arn
# Wait for a running execution to complete
wait_for_result(execution_arn: str, timeout: int = 60) -> DurableFunctionTestResult
Not applicable on the local runner. run() runs a single invocation,
runUntilComplete() drives the full loop. The cloud runner exposes startAsync(), see
CloudDurableTestRunner.
The local runner supports the async pattern, primarily for callback workflows:
// Start the workflow and return the durable execution ARN
Task<string> StartAsync(
TInput input, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
// Drive a started workflow to a terminal state
Task<TestResult<TOutput>> WaitForResultAsync(
string durableExecutionArn, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
StartAsync drives the workflow to its first suspension point and returns the ARN.
WaitForResultAsync must be preceded by a StartAsync on the same runner; it throws
InvalidOperationException otherwise. Use these together with WaitForCallbackAsync
and the SendCallback* methods to drive callback workflows.
Inspect operations¶
getOperation(name: string, index?: number): DurableOperation
getOperationByIndex(index: number): DurableOperation
getOperationByNameAndIndex(name: string, index: number): DurableOperation
getOperationById(id: string): DurableOperation
Parameters:
name(required) The operation name.index(optional) Zero-based index when multiple operations share the same name. Defaults to0.id(required) The unique operation ID.
Returns: DurableOperation
Not available on the runner. Inspect operations through the result:
result.get_step(name), result.get_wait(name), result.get_callback(name),
result.get_context(name), result.get_invoke(name),
result.get_operation_by_name(name), and result.get_all_operations(). See
TestResult.
Parameters:
name(required) The operation name.
Returns: TestOperation, or null if not found.
The .NET runner does not expose operation lookups; inspect operations through the
returned TestResult<TOutput> instead:
TestStep GetStep(string name) // throws if not found
TestStep? FindStep(string name) // null if not found
IReadOnlyList<TestStep> GetSteps(string name)
TestStep GetStepById(string operationId)
IReadOnlyList<TestStep> GetStepsByStatus(string status)
IReadOnlyList<TestStep> GetChildren(TestStep parent)
result.Steps also exposes the full list of recorded operations (excluding the
top-level execution). See TestResult.
Drive callbacks¶
Callback interaction is on the DurableOperation object. Get a handle with
getOperation() and then call waitForData() and sendCallback*() on it. See
Drive a callback from an operation.
# Wait for a callback to become available and return its ID
wait_for_callback(execution_arn: str, name: str | None = None, timeout: int = 60) -> str
# Send a successful callback result
send_callback_success(callback_id: str, result: bytes | None = None) -> None
# Send a callback failure
send_callback_failure(callback_id: str, error: ErrorObject | None = None) -> None
# Send a callback heartbeat
send_callback_heartbeat(callback_id: str) -> None
// Get the callback ID for a named callback operation
String getCallbackId(String operationName)
// Complete a callback with a success result
void completeCallback(String callbackId, String result)
// Fail a callback
void failCallback(String callbackId, ErrorObject error)
// Time out a callback
void timeoutCallback(String callbackId)
Callbacks are driven from the runner. After StartAsync, wait for the callback ID, then
send success, failure, or a heartbeat:
// Wait for a pending callback and return its ID
Task<string> WaitForCallbackAsync(
string durableExecutionArn, string? name = null,
TimeSpan? timeout = null, CancellationToken cancellationToken = default)
// Complete a callback with a success result
Task SendCallbackSuccessAsync<TResult>(
string callbackId, TResult result, CancellationToken cancellationToken = default)
// Fail a callback
Task SendCallbackFailureAsync(
string callbackId, ErrorObject? error = null, CancellationToken cancellationToken = default)
// Keep a callback alive
Task SendCallbackHeartbeatAsync(
string callbackId, CancellationToken cancellationToken = default)
There is no separate "time out" method: to simulate a timeout, fail the callback with an
ErrorObject or let the configured callback timeout elapse.
Drive chained invokes¶
Not applicable. Register a mock handler for the invoked function and let the test drive the real handler path. See Register mock handlers for invoke.
Not applicable.
// Complete a chained invoke with a success result
void completeChainedInvoke(String name, String result)
// Fail a chained invoke
void failChainedInvoke(String name, ErrorObject error)
// Time out a chained invoke
void timeoutChainedInvoke(String name)
// Stop a chained invoke
void stopChainedInvoke(String name, ErrorObject error)
The .NET SDK does not expose per-invoke completion methods. Instead, register the invoked function's handler on the runner and let the real invoke path run against it. See Register mock handlers for invoke. To make an invoke fail, throw from the registered handler.
Register mock handlers for invoke¶
// Register a durable function for context.invoke() calls
registerDurableFunction(functionName: string, handler: DurableLambdaHandler): this
// Register a standard Lambda function for context.invoke() calls
registerFunction(functionName: string, handler: Handler): this
Both methods return the runner for chaining.
Not applicable.
Not applicable.
// Register a durable sibling that the workflow invokes with context.InvokeAsync()
DurableTestRunner<TInput, TOutput> RegisterDurableFunction<TPayload, TResult>(
string functionNameOrArn,
Func<TPayload, IDurableContext, Task<TResult>> handler)
// Register a plain (non-durable) Lambda sibling, also invoked with context.InvokeAsync()
DurableTestRunner<TInput, TOutput> RegisterFunction<TPayload, TResult>(
string functionNameOrArn,
Func<TPayload, ILambdaContext, Task<TResult>> handler)
Both methods return the runner for chaining.
Simulate failures¶
Not applicable.
Not applicable.
The .NET SDK does not expose checkpoint-manipulation methods. To exercise failure and
retry paths, throw from inside a step and assert on TestStep.Attempt and the recorded
operation status. See the retry example in Authoring.
Control time¶
Pass { skipTime: true } to setupTestEnvironment(). Both context.wait() delays and
step retry delays complete in zero wall-clock time.
Set the DURABLE_EXECUTION_TIME_SCALE environment variable to a float that multiplies
context.wait() durations. Step retry delays use the configured
next_attempt_delay_seconds at real wall-clock time and the scale does not apply to
them.
runUntilComplete() calls advanceTime() after each invocation. When you call run()
directly, call advanceTime() yourself between invocations. advanceTime() marks
PENDING step retries as READY and completes STARTED waits without real-time sleeps.
Set SkipTime on TestRunnerOptions. When true (the default), both WaitAsync delays
and step/WaitForConditionAsync retry backoffs complete immediately instead of sleeping
for real wall-clock time. There is no manual advanceTime() call. RunAsync advances
time internally.
await using var runner = new DurableTestRunner<object, string>(
Workflow,
new TestRunnerOptions { SkipTime = true });
Set SkipTime = false to assert on real wait durations.
See Authoring: Skip time in tests for an overview.
Reset between runs¶
Clears the operation index, wait manager, and operation storage so the runner can be reused across tests.
Create a new DurableFunctionTestRunner instance per test.
Create a new LocalDurableTestRunner instance per test.
There is no reset(). A runner is single-use and not thread-safe: create a new
DurableTestRunner<TInput, TOutput> per test and dispose it with await using.
Reference types¶
LocalDurableTestRunnerSetupParameters¶
Fields:
skipTime(optional) Install fake timers so retry delays and waits complete instantly. Defaults tofalse.checkpointDelay(optional) Simulated delay in milliseconds on checkpoint API calls. Useful for surfacing race conditions.
Not applicable. Configure with the DURABLE_EXECUTION_TIME_SCALE environment variable
and the poll_interval constructor argument.
Not applicable. Configure with withDurableConfig, withOutputType, and
advanceTime() on the runner instance.
Configuration lives in the TestRunnerOptions record passed to the constructor:
public sealed record TestRunnerOptions
{
public bool SkipTime { get; init; } = true;
public int MaxInvocations { get; init; } = 100;
public TimeSpan DefaultTimeout { get; init; } = TimeSpan.FromSeconds(30);
public ILambdaSerializer? Serializer { get; init; }
public ILoggerFactory? LoggerFactory { get; init; }
public string DurableExecutionArn { get; init; } // synthetic test ARN by default
}
Fields:
SkipTime(optional) Complete waits and retry backoffs instantly. Defaults totrue(the opposite of the JavaScript SDK, where time-skipping is opt-in).MaxInvocations(optional) Maximum handler invocations before throwingTestExecutionLimitException. Defaults to100.DefaultTimeout(optional) Wall-clock timeout perRunAsync/WaitForResultAsynccall. Defaults to 30 seconds.Serializer(optional) AnILambdaSerializerfor result deserialization. Defaults toDefaultLambdaJsonSerializer.LoggerFactory(optional) AnILoggerFactoryfor runtime logging.DurableExecutionArn(optional) The ARN used in the test context. Defaults to a synthetic test ARN.
TestResult¶
The object returned by run(). Exposes the execution status, the final result, any
error, and the full operation history.
Status¶
Returns: ExecutionStatus (SUCCEEDED, FAILED, PENDING, or undefined).
Type: InvocationStatus (SUCCEEDED, FAILED, PENDING, TIMED_OUT, STOPPED).
Returns: ExecutionStatus (SUCCEEDED, FAILED, PENDING).
InvocationStatus Status { get; }
bool IsSucceeded { get; } // Status == InvocationStatus.Succeeded
bool IsFailed { get; } // Status == InvocationStatus.Failed
Type: InvocationStatus (Succeeded, Failed, Pending). There is no separate
execution-status enum in .NET; the cloud runner maps the service's finer terminal states
(FAILED, TIMED_OUT, STOPPED) onto InvocationStatus.Failed.
Result¶
Returns: The deserialized execution output, or undefined if not available.
Throws: The execution error if the execution failed.
<T> T getResult(Class<T> resultType)
<T> T getResult(TypeToken<T> resultType)
O getResult() // requires withOutputType() to be set
Returns: The deserialized execution output.
Throws: IllegalStateException if the execution did not succeed.
The deserialized execution output when Status is InvocationStatus.Succeeded;
otherwise the default value for TOutput. The result type is fixed at the runner's
TOutput type parameter, so no per-call type argument is needed. Call
EnsureSucceeded() first if you want a failed run to throw before you read Result.
Error¶
Operations¶
Parameters:
params(optional) Filter byOperationStatus.
Returns: Array of DurableOperation.
result.operations # list[Operation], top-level only
result.get_all_operations() # list[Operation], including nested
# Typed lookup by name
result.get_step(name: str) -> StepOperation
result.get_wait(name: str) -> WaitOperation
result.get_context(name: str) -> ContextOperation
result.get_callback(name: str) -> CallbackOperation
result.get_invoke(name: str) -> InvokeOperation
result.get_execution(name: str) -> ExecutionOperation
result.get_operation_by_name(name: str) -> Operation
Raises: DurableFunctionsTestError if the operation is not found.
List<TestOperation> getOperations()
List<TestOperation> getSucceededOperations()
List<TestOperation> getFailedOperations()
TestOperation getOperation(String name)
getOperation(name) returns null if not found.
IReadOnlyList<TestStep> Steps { get; } // all operations except the top-level execution
TestStep GetStep(string name) // throws if not found
TestStep? FindStep(string name) // null if not found
IReadOnlyList<TestStep> GetSteps(string name) // all matches (parallel branches, map items)
TestStep GetStepById(string operationId)
IReadOnlyList<TestStep> GetStepsByStatus(string status) // pass OperationStatus constants
IReadOnlyList<TestStep> GetChildren(TestStep parent)
Filter Steps by kind with LINQ, e.g.
result.Steps.Where(s => s.Kind == OperationKind.Step). Use the OperationStatus
string constants (e.g. OperationStatus.Succeeded) with GetStepsByStatus.
History events¶
Not available on the test result.
The .NET TestResult<TOutput> does not expose raw history events. Assert on the folded
operations through Steps and the TestStep accessors instead. (Internally the cloud
runner reconstructs operations from the history event stream, but that stream is not
surfaced on the result.)
Invocations¶
Useful for asserting on the number of Lambda re-invocations the test runner drove.
Not available on the test result.
Not available on the test result.
Pretty-print¶
Writes a formatted table of operations to stdout.
Not applicable.
Not applicable.
The .NET SDK does not expose a pretty-print method on the result. Iterate result.Steps
and format them yourself, e.g. with a foreach over Name, Kind, and Status.
Reference types¶
TestResultError¶
Uses ErrorObject from the main SDK:
Uses ErrorObject from software.amazon.awssdk.services.lambda.model:
Operation¶
Represents a single entry in the operation history. Each type of operation exposes its own details block (step, wait, callback, chained invoke, context, execution) on top of a shared set of accessors.
Common accessors¶
getName(): string | undefined
getType(): OperationType | undefined
getSubType(): OperationSubType | undefined
getStatus(): OperationStatus | undefined
getStartTimestamp(): Date | undefined
getEndTimestamp(): Date | undefined
getId(): string | undefined
getParentId(): string | undefined
getOperationData(): Operation | undefined
getEvents(): Event[] | undefined
getChildOperations(): DurableOperation[] | undefined
isWaitForCallback(): boolean
isCallback(): boolean
Every operation type inherits these fields from the base Operation dataclass:
The docs "Operation" type maps to TestStep in .NET. Common accessors:
string Id { get; }
string? Name { get; }
string? ParentId { get; }
OperationKind Kind { get; } // Step, Wait, Callback, ChainedInvoke, Context, Execution
string? SubKind { get; } // e.g. "Parallel", "Map", "WaitForCallback"
string Status { get; } // compare against OperationStatus constants
int Attempt { get; } // 1-based for steps, 0 for other kinds
DateTimeOffset? StartedAt { get; }
DateTimeOffset? EndedAt { get; }
TimeSpan? Duration { get; }
IReadOnlyList<TestStep> Children { get; }
Step details¶
TestStep exposes step details through kind-aware accessors rather than a separate
details object:
T? GetResult<T>() // deserializes the step result
ErrorObject? GetError() // the step error, or null
int Attempt { get; } // retry attempt (1-based)
GetResult<T>() routes to the right details block based on Kind, so it also works for
chained-invoke, context, and callback operations.
Wait details¶
WaitResultDetails exposes waitSeconds and scheduledEndTimestamp.
Callback details¶
Chained invoke details¶
Context details¶
ctx.result: OperationPayload | None
ctx.error: ErrorObject | None
ctx.child_operations: list[Operation]
# Typed lookup among the context's children
ctx.get_step(name) -> StepOperation
ctx.get_wait(name) -> WaitOperation
ctx.get_context(name) -> ContextOperation
ctx.get_callback(name) -> CallbackOperation
ctx.get_invoke(name) -> InvokeOperation
Execution details¶
Drive a callback from an operation¶
waitForData(status?: WaitingOperationStatus): Promise<DurableOperation>
sendCallbackSuccess(result?: string): Promise<SendDurableExecutionCallbackSuccessResponse>
sendCallbackFailure(error?: ErrorObject): Promise<SendDurableExecutionCallbackFailureResponse>
sendCallbackHeartbeat(): Promise<SendDurableExecutionCallbackHeartbeatResponse>
Driven from the runner. See LocalDurableTestRunner: Drive callbacks.
Driven from the runner. See LocalDurableTestRunner: Drive callbacks.
Driven from the runner, not from the TestStep. Use WaitForCallbackAsync to get the
callback ID and the SendCallback* methods to deliver a result. See
LocalDurableTestRunner: Drive callbacks.
Enums¶
Execution status¶
The terminal status of a durable execution.
ExecutionStatus from @aws-sdk/client-lambda:
| Value | Meaning |
|---|---|
SUCCEEDED |
Execution completed successfully |
FAILED |
Execution failed |
PENDING |
Execution is waiting (callback, invoke, etc.) |
TIMED_OUT |
Execution exceeded its timeout |
STOPPED |
Execution was stopped |
InvocationStatus from aws_durable_execution_sdk_python.execution:
| Value | Meaning |
|---|---|
SUCCEEDED |
Execution completed successfully |
FAILED |
Execution failed |
PENDING |
Execution is waiting |
TIMED_OUT |
Execution exceeded its timeout |
STOPPED |
Execution was stopped |
ExecutionStatus from software.amazon.lambda.durable.model:
| Value | Meaning |
|---|---|
SUCCEEDED |
Execution completed successfully |
FAILED |
Execution failed |
PENDING |
Execution is waiting |
InvocationStatus from Amazon.Lambda.DurableExecution:
| Value | Meaning |
|---|---|
Succeeded |
Execution completed successfully |
Failed |
Execution failed |
Pending |
Execution is waiting |
There is no separate execution-status enum. The cloud runner maps the service's
TIMED_OUT and STOPPED terminal states onto Failed.
Operation status¶
The status of an individual operation.
OperationStatus from @aws-sdk/client-lambda:
| Value | Meaning |
|---|---|
STARTED |
Operation is running |
SUCCEEDED |
Operation completed successfully |
FAILED |
Operation failed |
PENDING |
Operation is queued |
CANCELLED |
Operation was cancelled |
TIMED_OUT |
Operation exceeded its timeout |
STOPPED |
Operation was stopped |
OperationStatus from aws_durable_execution_sdk_python.lambda_service. Same values as
TypeScript.
OperationStatus from software.amazon.awssdk.services.lambda.model. Same values as
TypeScript.
OperationStatus from Amazon.Lambda.DurableExecution.Testing is a static class of
string constants (compare against TestStep.Status), not an enum:
| Constant | Meaning |
|---|---|
OperationStatus.Started |
Operation is running |
OperationStatus.Succeeded |
Operation completed successfully |
OperationStatus.Failed |
Operation failed |
OperationStatus.Pending |
Operation is queued |
OperationStatus.Cancelled |
Operation was cancelled |
OperationStatus.TimedOut |
Operation exceeded its timeout |
OperationStatus.Stopped |
Operation was stopped |
OperationStatus.Ready |
Operation is ready to resume |
Operation type¶
OperationType from @aws-sdk/client-lambda:
| Value | Meaning |
|---|---|
STEP |
A step operation |
WAIT |
A wait operation |
CALLBACK |
A callback operation |
CHAINED_INVOKE |
An invoke operation |
CONTEXT |
A child context |
EXECUTION |
The root execution operation |
OperationType from aws_durable_execution_sdk_python.lambda_service. Same values as
TypeScript.
OperationType from software.amazon.awssdk.services.lambda.model. Same values as
TypeScript.
OperationKind from Amazon.Lambda.DurableExecution.Testing (read via TestStep.Kind):
| Value | Meaning |
|---|---|
OperationKind.Step |
A step operation |
OperationKind.Wait |
A wait operation |
OperationKind.Callback |
A callback operation |
OperationKind.ChainedInvoke |
An invoke operation |
OperationKind.Context |
A child context |
OperationKind.Execution |
The root execution operation |
Waiting operation status¶
WaitingOperationStatus from @aws/durable-execution-sdk-js-testing:
| Value | Meaning |
|---|---|
STARTED |
Fires when the operation starts |
SUBMITTED |
For callbacks: fires when the submitter function completes. For other operations: same as COMPLETED |
COMPLETED |
Fires when the operation reaches a terminal status |
Not applicable. Use runner.wait_for_callback() to wait for a callback to become
available.
Not applicable. Use runner.getCallbackId() after run() returns PENDING.
The .NET SDK does not expose a waiting-operation-status enum. After StartAsync, call
WaitForCallbackAsync(arn, name) to obtain the callback ID; the OperationStatus
constants cover the operation lifecycle states.
CloudDurableTestRunner¶
Invokes a deployed Lambda function, polls for completion, and retrieves the full
operation history for assertions. Use it to validate deployment, IAM permissions, and
real service integrations. Both runners share the same TestResult and Operation
types, so tests written against the local runner run unchanged against the cloud runner.
Create a runner¶
new CloudDurableTestRunner({
functionName: string,
client?: LambdaClient,
config?: CloudDurableTestRunnerConfig,
})
Parameters:
functionName(required) The function name or ARN. A qualifier is required for durable functions.client(optional) A configuredLambdaClient. Defaults tonew LambdaClient().config(optional) ACloudDurableTestRunnerConfigobject.
DurableFunctionCloudTestRunner(
function_name: str,
region: str = "us-west-2",
lambda_endpoint: str | None = None,
poll_interval: float = 1.0,
)
Parameters:
function_name(required) The function name or ARN.region(optional) AWS region. Defaults to"us-west-2".lambda_endpoint(optional) Custom Lambda endpoint URL. Defaults toNone.poll_interval(optional) Seconds between status polls. Defaults to1.0.
// Class-based types
CloudDurableTestRunner.create(String functionArn, Class<I> inputType, Class<O> outputType)
// TypeToken-based types
CloudDurableTestRunner.create(String functionArn, TypeToken<I> inputType, TypeToken<O> outputType)
// With custom LambdaClient
CloudDurableTestRunner.create(String functionArn, Class<I> inputType, Class<O> outputType, LambdaClient lambdaClient)
Override settings on an existing runner:
CloudDurableTestRunner<I, O> withLambdaClient(LambdaClient lambdaClient)
CloudDurableTestRunner<I, O> withPollInterval(Duration interval)
CloudDurableTestRunner<I, O> withTimeout(Duration timeout)
CloudDurableTestRunner<I, O> withInvocationType(InvocationType type)
CloudDurableTestRunner<I, O> withSerDes(SerDes serDes)
Parameters:
functionArn(required) The function ARN. A qualifier is required for durable functions.inputType(required) The input type class orTypeToken.outputType(required) The output type class orTypeToken.lambdaClient(optional) A configuredLambdaClient. Defaults to a client usingDefaultCredentialsProvider.
CloudDurableTestRunner(
string functionArn,
IAmazonLambda? lambdaClient = null,
CloudTestRunnerOptions? options = null)
await using var runner = new CloudDurableTestRunner<OrderInput, OrderResult>(
"arn:aws:lambda:us-east-1:123456789012:function:my-fn:live");
Parameters:
functionArn(required) The qualified function ARN (with alias, version, or$LATEST). A qualifier is required for durable functions.lambdaClient(optional) AnIAmazonLambdaclient. When null, the runner creates and owns anAmazonLambdaClientusing the default credential chain and disposes it onDisposeAsync.options(optional) ACloudTestRunnerOptionsrecord for poll intervals, timeout, and serializer.
The input and output types are the runner's type parameters, so no separate inputType
or outputType argument is needed.
Run the handler¶
Parameters:
params(optional) AnInvokeRequestobject.payload(optional) The input payload.
Returns: Promise<TestResult>
Parameters:
input(optional) JSON-encoded input string.timeout(optional) Maximum seconds to wait. Defaults to60.
Returns: DurableFunctionTestResult
Raises: TimeoutError if the execution does not complete within timeout.
Parameters:
input(required) The handler input.
Returns: TestResult<O>
Task<TestResult<TOutput>> RunAsync(
TInput input,
TimeSpan? timeout = null,
CancellationToken cancellationToken = default)
Invokes the deployed function (Event invocation), polls the durable-execution history
until the execution reaches a terminal state, and returns the folded result. This is the
same signature as the local runner, so tests written against
IDurableTestRunner<TInput, TOutput> run unchanged on either backend.
Parameters:
input(required) The handler input.timeout(optional) Wall-clock timeout. Defaults toCloudTestRunnerOptions.DefaultTimeout(5 minutes).cancellationToken(optional) ACancellationToken.
Returns: Task<TestResult<TOutput>>
Run asynchronously¶
Not applicable. run() already drives the full replay loop.
The returned AsyncExecution<O> exposes pollUntil(), pollUntilComplete(),
isComplete(), hasOperation(), hasCallback(), getCallbackId(), getOperation(),
getOperations(), getStatus(), getExecutionArn(), completeCallback(),
failCallback(), and heartbeatCallback().
The .NET SDK does not return a dedicated async-execution handle. Use the same
StartAsync + WaitForResultAsync pair as the local runner:
Task<string> StartAsync(
TInput input, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
Task<TestResult<TOutput>> WaitForResultAsync(
string durableExecutionArn, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
StartAsync fires an Event invocation and resolves the durable execution ARN by
listing executions. Drive callbacks with WaitForCallbackAsync and the SendCallback*
methods between the two calls.
Inspect operations¶
Inspect operations through the test result. See TestResult.
Inspect operations through the returned TestResult<TOutput>. The cloud
result exposes the same Steps list and GetStep/FindStep/GetSteps accessors as the
local runner. See TestResult.
Drive callbacks¶
Callback interaction is on the DurableOperation object. See
Drive a callback from an operation.
Drive callbacks through the AsyncExecution<O> returned by startAsync(). Use
getCallbackId(), completeCallback(), failCallback(), and heartbeatCallback() on
the async handle.
Callbacks are driven from the runner, same as the local runner. After StartAsync, call
WaitForCallbackAsync and then SendCallbackSuccessAsync, SendCallbackFailureAsync,
or SendCallbackHeartbeatAsync. On the cloud runner these issue the corresponding
SendDurableExecutionCallback* Lambda API calls.
Configure polling and timeouts¶
Pass config: { pollInterval, invocationType } to the constructor. See
CloudDurableTestRunnerConfig.
Pass poll_interval to the constructor. Pass timeout to run() or run_async() to
set the maximum wait.
Use withPollInterval(Duration), withTimeout(Duration), and
withInvocationType(InvocationType) on the runner.
Configure polling and timeout through the CloudTestRunnerOptions record passed to the
constructor. Per-call timeouts can also be passed to RunAsync/WaitForResultAsync:
await using var runner = new CloudDurableTestRunner<OrderInput, OrderResult>(
functionArn,
options: new CloudTestRunnerOptions
{
InitialPollInterval = TimeSpan.FromMilliseconds(200),
PollInterval = TimeSpan.FromSeconds(2),
DefaultTimeout = TimeSpan.FromMinutes(5),
});
The invocation type is fixed to Event (fire-and-forget) so callback workflows do not
deadlock; there is no invocationType knob.
Reset between runs¶
Reference types¶
CloudDurableTestRunnerConfig¶
Fields:
pollInterval(optional) Milliseconds between history polls. Defaults to1000.invocationType(optional) Lambda invocation type. Defaults toInvocationType.RequestResponse.
Not a separate config object. Pass poll_interval directly to the constructor.
Not a separate config object. Use the with* builder methods on the runner.
The .NET equivalent is the CloudTestRunnerOptions record:
public sealed record CloudTestRunnerOptions
{
public TimeSpan InitialPollInterval { get; init; } = TimeSpan.FromMilliseconds(200);
public TimeSpan PollInterval { get; init; } = TimeSpan.FromSeconds(2);
public TimeSpan DefaultTimeout { get; init; } = TimeSpan.FromMinutes(5);
public ILambdaSerializer? Serializer { get; init; }
}
Fields:
InitialPollInterval(optional) Delay before the first poll retry; subsequent delays grow exponentially up toPollInterval. Defaults to 200 milliseconds.PollInterval(optional) Maximum steady-state interval between polls. Defaults to 2 seconds.DefaultTimeout(optional) Wall-clock timeout for polling. Defaults to 5 minutes.Serializer(optional) AnILambdaSerializerfor payload and result serialization. Defaults toDefaultLambdaJsonSerializer.
See also¶
- Authoring Set up the local runner and write your first test.
- Assertions Inspect steps, waits, and callbacks after a test run.
- Workflow patterns Complete tests for common workflow shapes.
- Cloud Runner Run tests against a deployed Lambda function.
- Runner How the replay loop and checkpointing work.