CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

testland/aws-sam-local-testing

Use when AWS Lambda functions with API Gateway need testing locally: sam local invoke with event payloads, start-api for a local API Gateway, start-lambda for SDK clients and generate-event, plus .NET Lambda handler tests with Amazon.Lambda.TestUtilities.

Quality

89%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

dotnet.mdreferences/

.NET Lambda testing - Amazon.Lambda.TestUtilities and the dotnet-lambda CLI

For C#/.NET Lambdas the fast path is handler-direct invocation with a mock context, not spawning sam local invoke per test. AWS's canonical toolkit is aws-lambda-dotnet: Amazon.Lambda.TestUtilities for library-level fakes plus the Mock Lambda Test Tool UI for manual invocation.

Install

dotnet add package Amazon.Lambda.Core
dotnet add package Amazon.Lambda.Serialization.SystemTextJson
dotnet add package Amazon.Lambda.TestUtilities
dotnet add package Microsoft.NET.Test.Sdk
dotnet add package xunit

Handler + TestLambdaContext

Per Amazon.Lambda.TestUtilities:

using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.SystemTextJson;

[assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]

public class Functions
{
    public string Handler(string input, ILambdaContext context)
    {
        context.Logger.LogLine($"Got input: {input}");
        return input.ToUpper();
    }
}
using Amazon.Lambda.TestUtilities;
using Xunit;

[Fact]
public void Handler_Uppercases()
{
    var context = new TestLambdaContext
    {
        FunctionName = "test-fn",
        RemainingTime = TimeSpan.FromSeconds(30),  // Logger auto-set to TestLambdaLogger
    };
    Assert.Equal("HELLO", new Functions().Handler("hello", context));
}

[Fact]
public void Handler_LogsInput()
{
    var context = new TestLambdaContext();
    new Functions().Handler("hi", context);
    var logger = (TestLambdaLogger)context.Logger;
    Assert.Contains("Got input: hi", logger.Buffer.ToString());
}

Remaining-time behaviour

Set RemainingTime low to exercise timeout-aware handlers (the early-return pattern in the timeout-budgets reference of serverless-integration-test-builder):

var context = new TestLambdaContext { RemainingTime = TimeSpan.FromSeconds(3) };
var result = new Functions().Handler("work-that-takes-time", context);
Assert.Contains("partial", result);

Serialised event payloads

var json = File.ReadAllText("Events/apigw-request.json");   // from sam local generate-event
var request = new DefaultLambdaJsonSerializer().Deserialize<APIGatewayProxyRequest>(json);
var response = new Functions().HandleApi(request, new TestLambdaContext());
Assert.Equal(200, response.StatusCode);

dotnet-lambda CLI (deploy + invoke path)

Per aws-extensions-for-dotnet-cli:

dotnet tool install -g Amazon.Lambda.Tools
dotnet lambda invoke-function MyFunction --payload '"hello"'

For local-only testing, prefer handler-direct invocation.

CI

jobs:
  dotnet-lambda-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-dotnet@v4
        with: { dotnet-version: '8.0.x' }
      - run: dotnet restore
      - run: dotnet test --no-build --verbosity normal

Anti-patterns

Anti-patternWhy it failsFix
Spawn dotnet lambda invoke per testNetwork calls; slow; rate-limitedHandler-direct invocation
Skip TestLambdaContextNull context fails at runtimeAlways pass one
RemainingTime = TimeSpan.MaxValueTimeout logic never exercisedRealistic remaining time
Hand-rolled APIGatewayProxyRequestSchema driftsam local generate-event fixture
Missing [assembly: LambdaSerializer]Runtime deserialization failsRegister the serializer in tests too
Mocking the LoggerLoses TestLambdaLogger.Buffer replayUse the default TestLambdaContext logger

Limitations

  • In-process tests use the standard JIT; ReadyToRun / Native AOT Lambdas behave differently - pair with deployed-Lambda tests.
  • The Lambda runtime API (next/response polling) is not exercised.
  • Cold-start behaviour is invisible warm-in-process; see the parent skill's budget tables.

References

references

SKILL.md

tile.json