CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/aws-sam-local-testing

Wraps AWS SAM (Serverless Application Model) Local CLI for testing Lambda functions locally: `sam local invoke` (single invocation with event payload), `sam local start-api` (local API Gateway emulator), `sam local start-lambda` (local Lambda invoke endpoint for AWS SDK clients), and event-payload generation (`sam local generate-event`). For C#/.NET Lambdas, references/dotnet.md covers handler-direct testing with Amazon.Lambda.TestUtilities (TestLambdaContext, TestLambdaLogger) and the dotnet-lambda CLI. Use when testing Lambda + API Gateway + integrated AWS services locally.

72

Quality

91%

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 cold-start-budget-reference references/timeout-budgets.md):

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