Exam Guide: Developer – Associate
ποΈ Domain 3: Deployment
π Task 2: Test Applications In Development Environments
Testing on AWS isn’t just about unit tests. You need to test locally with SAM CLI, write integration tests against deployed stages, mock AWS services and external APIs, validate event-driven flows, and use API Gateway stages for environment isolation.
πConcepts
The Testing Pyramid
Level Speed Scope AWS Services Tools Unit Tests Fast (ms) Single function, no external calls Mocked pytest, moto, unittest.mock Integration Tests Medium (seconds) Multiple services working together Real (deployed) pytest + requests, deployed API Gateway stage End-to-end Tests Slow (secondsβminutes) Full user workflow Real (deployed) Selenium, Postman, curl against live APIπ‘ Unit tests use mocks (moto for AWS, unittest.mock for external APIs). Integration tests run against real deployed resources.
SAM Local Testing Capabilities
Command
What It Does
When to Use
sam local invoke
Runs a single Lambda function locally in a Docker container
Testing individual function logic with a specific event
sam local start-api
Starts a local API Gateway emulator
Testing full API request/response flow locally
sam local start-lambda
Starts a local Lambda endpoint for SDK calls
Testing code that invokes Lambda via the SDK
sam local generate-event
Generates sample event payloads for AWS services
Creating test events for S3, SQS, API Gateway, etc.
β οΈ Key Details:
- SAM local uses Docker to simulate the Lambda runtime environment
- It reads your
template.yamlto understand function configuration - Environment variables can be overridden with
--env-vars env.json - It does not mock AWS services, therefore if your function calls DynamoDB, it calls real DynamoDB (or you need moto)
π‘
sam local invokeruns a function once and exits.sam local start-apikeeps running and accepts HTTP requests. Both use Docker containers that match the Lambda runtime. Know that SAM local does NOT mock AWS services. Your function still needs real credentials or mocked services.
Mocking Strategies
What to Mock Tool How It Works AWS Services (DynamoDB, S3, SQS, etc.) moto (@mock_aws)
Intercepts boto3 calls and returns realistic responses
External HTTP APIs
unittest.mock (@patch)
Replaces the HTTP client with a mock that returns controlled responses
Environment Variables
os.environ or monkeypatch
Set test values for TABLE_NAME, STAGE, etc.
Lambda Context
Custom object
Create a simple object with function_name, memory_limit_in_mb, etc.
API Gateway Stages for Environment Isolation
StageURL Pattern
Use Case
dev
https://{api-id}.execute-api.{region}.amazonaws.com/dev
Development and local integration testing
staging
https://{api-id}.execute-api.{region}.amazonaws.com/staging
QA and pre-production testing
prod
https://{api-id}.execute-api.{region}.amazonaws.com/prod
Production traffic
Each stage can have its own:
- Stage Variables: different table names, feature flags, log levels per stage
- Throttling Settings: different rate limits per stage
- Logging Configuration: verbose logging in dev, errors only in prod
π‘ Stage variables are accessible in Lambda via
event['stageVariables']. They let you point different stages at different backends (different DynamoDB tables, different Lambda aliases) without changing code.
Event-Driven Testing Approaches
Approach What It Tests How SAM Local With Generated Events Function logic with realistic payloadssam local generate-event β sam local invoke
Console Test Events
Function logic in the deployed environment
Create test events in the Lambda console
EventBridge Test Events
Rule matching and target invocation
Send test events via the EventBridge console
SQS Test Messages
Queue-triggered function processing
Send messages via the SQS console
CloudWatch Logs
Verify function executed correctly
Check logs after sending test events
ποΈ Build A Testing Toolkit
Build a Testing Toolkit that demonstrates testing approaches:
- Local Lambda testing with SAM CLI (
invokeandstart-api) - Unit tests using moto to mock DynamoDB and S3
- Integration tests running against a deployed API Gateway stage
- EventBridge rule testing with test events in the console
- Sample event generation with
sam local generate-event
Prerequisites
β οΈ Before You Start Read This
- π‘ SAM local does NOT mock AWS.
sam local invokeandsam local start-apirun your code in a container but call real AWS services with your real credentials. So we create the DynamoDB table first.- π‘ API Gateway routes come from the template, not your code. A path only exists if it’s declared in the template’s
Events.GET /will always say “Missing Authentication Token” because there’s no root route.- π‘ Region must be consistent across your credentials, the table, and
env.json. We pinus-east-1everywhere so change it only if you use a different region, but change it everywhere.- π‘ Windows files need UTF-8 without BOM. A BOM causes
Unable to unmarshal input: Expecting value: line 1 column 1. Create JSON files in VS Code and check the encoding in the bottom-right status bar.- π‘ After editing
template.yaml, alwayssam buildthen restartstart-api. The local server serves the built template in.aws-sam/build/, not your edited source.
Step 00: Set your region once for this session so every command agrees:
$env:AWS_REGION = "us-east-1"
aws configure set region us-east-1
Enter fullscreen mode Exit fullscreen mode
β οΈ If you already use a different region, substitute it consistently in every command and file below.
Step 01: Create the DynamoDB Table First
β οΈ Because SAM local calls real DynamoDB, the table must exist before you invoke anything.
aws dynamodb create-table `
--table-name dev-orders `
--attribute-definitions AttributeName=PK,AttributeType=S AttributeName=SK,AttributeType=S `
--key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE `
--billing-mode PAY_PER_REQUEST `
--region us-east-1
Enter fullscreen mode Exit fullscreen mode
π‘ The backtick
`is PowerShell’s line-continuation character. On macOS/Linux/CloudShell, use\instead.β οΈ Wait until the table is
ACTIVE:
aws dynamodb describe-table --table-name dev-orders --region us-east-1 --query "Table.TableStatus"
Enter fullscreen mode Exit fullscreen mode
β οΈ Repeat until it prints
"ACTIVE"(usually a few seconds).π‘ The table’s key schema mirrors single-table design.
PK(partition key) +SK(sort key) let one table hold many item types.
Step 02: Create the SAM Project
sam init --runtime python3.13 --name testing-toolkit --app-template hello-world
cd testing-toolkit
Enter fullscreen mode Exit fullscreen mode
π‘This scaffolds a project with
hello_world/app.py,template.yaml, andtests/.
Step 03: Replace the Function Code
Open hello_world/app.py and replace its entire contents with this:
import json
import os
from datetime import datetime
import boto3
# π‘ Initialize the client OUTSIDE the handler so it's reused across warm
# invocations. Creating it inside the handler would rebuild it every call.
dynamodb = boto3.resource("dynamodb")
TABLE_NAME = os.environ.get("TABLE_NAME", "dev-orders")
def lambda_handler(event, context):
"""Order API: create an order (POST) or fetch one (GET)."""
table = dynamodb.Table(TABLE_NAME)
method = event.get("httpMethod", "GET")
path = event.get("path", "/")
try:
# --- Create an order ---
if method == "POST" and path == "/orders":
body = json.loads(event.get("body") or "{}")
order_id = f"ORD-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
table.put_item(Item={
"PK": f"ORDER#{order_id}",
"SK": "METADATA",
"orderId": order_id,
"customerId": body.get("customerId", "unknown"),
"items": body.get("items", []),
"status": "created",
"createdAt": datetime.utcnow().isoformat(),
})
return _response(201, {"orderId": order_id, "status": "created"})
# --- Get a single order ---
if method == "GET" and path.startswith("/orders/"):
order_id = event["pathParameters"]["orderId"]
result = table.get_item(Key={"PK": f"ORDER#{order_id}", "SK": "METADATA"})
item = result.get("Item")
if not item:
return _response(404, {"error": f"Order {order_id} not found"})
return _response(200, item)
return _response(200, {"message": "Testing Toolkit API",
"stage": os.environ.get("STAGE", "local")})
except Exception as e:
# π‘ Always handle exceptions. An uncaught error becomes a generic
# 500 "Internal server error" at API Gateway, hiding the real cause.
print(f"ERROR: {type(e).__name__}: {e}")
return _response(500, {"error": type(e).__name__, "detail": str(e)})
def _response(status_code, body):
return {
"statusCode": status_code,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(body, default=str),
}
Enter fullscreen mode Exit fullscreen mode
π‘ The
try/exceptmatters for debugging. Without it, a failed DynamoDB call throws an uncaught exception and API Gateway returns a bareInternal server error. By catching it and returning the error name, you can see why it failed in the HTTP response itself.
Step 04: Fix the Template Routes
β οΈ The default template only maps
GET /hello. Opentemplate.yamland replace the entireResources:section’sHelloWorldFunctionso it matches your code’s routes. YourHelloWorldFunctionblock should look exactly like this:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.13
Timeout: 10
Environment:
Variables:
TABLE_NAME: dev-orders
STAGE: local
Policies:
- DynamoDBCrudPolicy:
TableName: dev-orders
Events:
CreateOrder:
Type: Api
Properties:
Path: /orders
Method: post
GetOrder:
Type: Api
Properties:
Path: /orders/{orderId}
Method: get
Enter fullscreen mode Exit fullscreen mode
π‘ Routes are configuration, not code. API Gateway only serves paths declared under
Events. Your function’s internalif path == "/orders"logic never runs unless the template routes that path to it. This is why unknown paths return “Missing Authentication Token.”π‘
DynamoDBCrudPolicyis a SAM policy template. It grants least-privilege CRUD access to just the named table, instead of a broadAmazonDynamoDBFullAccess.
Step 05: Create the Environment Variable File
β οΈ SAM local reads env vars from a JSON file. Create a file named
env.jsonin the project root (same folder astemplate.yaml) with this content:
{
"HelloWorldFunction": {
"TABLE_NAME": "dev-orders",
"STAGE": "local",
"AWS_REGION": "us-east-1"
}
}
Enter fullscreen mode Exit fullscreen mode
β οΈ Windows Issue: Create this file in VS Code. Look at the bottom-right status bar. If it says “UTF-8 with BOM”, click it β Save with Encoding β UTF-8. A BOM breaks JSON parsing with
Expecting value: line 1 column 1 (char 0).π‘ The top-level key is the function’s logical ID.
HelloWorldFunctionmatches the resource name intemplate.yaml. PinningAWS_REGIONhere guarantees the function looks for the table in the same region you created it.
Step 06: Create a Test Event File
Create a file create_order.json inside the events/ folder :
{
"httpMethod": "POST",
"path": "/orders",
"headers": { "Content-Type": "application/json" },
"pathParameters": null,
"body": "{\"customerId\": \"CUST-001\", \"items\": [{\"productId\": \"PROD-A\", \"quantity\": 2}]}"
}
Enter fullscreen mode Exit fullscreen mode
π‘ This mimics the API Gateway proxy event. When API Gateway invokes Lambda, it wraps the HTTP request in this structure.
bodyis a JSON string (escaped), not an object. That’s why the code doesjson.loads(event["body"]).β οΈ Save as UTF-8 without BOM.
Step 07: Build
sam build
Enter fullscreen mode Exit fullscreen mode
π‘ Always build after editing
template.yamlor your code.sam buildcopies everything into.aws-sam/build/, which is whatsam localactually runs. Skipping this means you test stale code/routes.β οΈ If
sam buildcomplains it can’t find Python 3.13, runsam build --use-container(needs Docker running). It builds inside a Python 3.13 image so your local Python version doesn’t matter.
Step 08: Test with sam local invoke (Direct Function Test)
This invokes the function once with your test event. No API Gateway involved.
sam local invoke HelloWorldFunction -e events/create_order.json --env-vars env.json
Enter fullscreen mode Exit fullscreen mode
Expected Result: a 201 response with an orderId, and no errors.
π‘
sam local invokebypasses API Gateway. It calls the handler directly with the event you pass. Routing doesn’t matter here, only the function logic and its (real) AWS calls. Because thedev-orderstable exists inus-east-1, theput_itemsucceeds.β οΈ If you see
ResourceNotFoundException, the table isn’t in the region the function is using.
Step 09: Verify the item actually landed in DynamoDB:
aws dynamodb scan --table-name dev-orders --region us-east-1 --query "Items"
Enter fullscreen mode Exit fullscreen mode
You should see the order you just created.
Step 10: Test with sam local start-api (Full HTTP Test)
Now test the real HTTP routing. Start the local API in one terminal:
sam local start-api --port 3000 --env-vars env.json
Enter fullscreen mode Exit fullscreen mode
Leave this running.
π‘ The function logs (including real errors) print in THIS terminal. If an HTTP call returns 500, look here for the actual stack trace.
Open a second PowerShell terminal and send requests.
Step 11: Create an order (POST)
β οΈ On Windows, use
Invoke-RestMethod. PowerShell’scurlis an alias forInvoke-WebRequestwith different syntax, and inlinecurl.exeJSON escaping is painful.
Invoke-RestMethod -Uri http://localhost:3000/orders -Method Post -ContentType "application/json" -Body '{"customerId": "CUST-001", "items": [{"productId": "PROD-A", "quantity": 2}]}'
Enter fullscreen mode Exit fullscreen mode
macOS / Linux / CloudShell equivalents
curl -X POST http://localhost:3000/orders \
-H "Content-Type: application/json" \
-d '{"customerId": "CUST-001", "items": [{"productId": "PROD-A", "quantity": 2}]}'
curl http://localhost:3000/orders/ORD-20260702093000
Enter fullscreen mode Exit fullscreen mode
Expected Result: an object with orderId and status: created.
Step 12: Get that order (GET)
Copy the orderId from the previous response and:
Invoke-RestMethod -Uri http://localhost:3000/orders/ORD-20260702093000
Enter fullscreen mode Exit fullscreen mode
(Replace with your actual order ID.)
Expected Result: the full order item.
orderId : ORD-20260702112404
status : created
createdAt : 2026-07-02T11:24:04.213247
PK : ORDER#ORD-20260702112404
items : {@{productId=PROD-A; quantity=2}}
customerId : CUST-001
SK : METADATA
Enter fullscreen mode Exit fullscreen mode
π‘ Expected “errors” that are actually correct:
GET http://localhost:3000/β “Missing Authentication Token:” there’s no root route. Fine.GET http://localhost:3000/orders(no ID) β “Missing Authentication Token:” βPOST /ordersandGET /orders/{orderId}exist. Fine.
Stop the server with Ctrl+C when done. If port 3000 stays stuck:
Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess | Stop-Process -Force
Enter fullscreen mode Exit fullscreen mode
Step 13: Unit Tests with moto (No AWS Needed)
π‘ It needs no real AWS, no Docker, no network.
motomocks AWS services in memory, so tests are fast and isolated.
pip install pytest moto boto3
Enter fullscreen mode Exit fullscreen mode
β οΈ Windows Path-Length If you installed Python from the Microsoft Store, its packages live under a very long base path (
AppData\Local\Packages\PythonSoftwareFoundation...\LocalCache\...), and moto’s deeply nested files push past Windows’ 260-character limit, failing withOSError: [Errno 2] No such file or directory. Note thatmoto[dynamodb]does not help The extra only changes dependencies, not the files installed. Two fixes:Fix A (permanent, recommended): Enable long paths. In an Administrator PowerShell, run
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force, then reboot and re-run the install.Fix B (no admin): Use a virtual environment at a short path so the total path stays under the limit:
python -m venv C:\venvthenC:\venv\Scripts\Activate.ps1thenpip install pytest moto boto3. Don’t put the venv inside the deep project folder. UseC:\venv.
Step 14: Create tests/unit/test_app.py:
import json
import os
import boto3
import pytest
from moto import mock_aws
@pytest.fixture
def dynamodb_table():
"""π‘ moto intercepts boto3 calls and simulates DynamoDB in memory.
We create the table inside the mock BEFORE importing the handler."""
with mock_aws():
os.environ["AWS_DEFAULT_REGION"] = "us-east-1"
os.environ["TABLE_NAME"] = "dev-orders"
client = boto3.resource("dynamodb", region_name="us-east-1")
client.create_table(
TableName="dev-orders",
KeySchema=[
{"AttributeName": "PK", "KeyType": "HASH"},
{"AttributeName": "SK", "KeyType": "RANGE"},
],
AttributeDefinitions=[
{"AttributeName": "PK", "AttributeType": "S"},
{"AttributeName": "SK", "AttributeType": "S"},
],
BillingMode="PAY_PER_REQUEST",
)
yield
def test_create_order_returns_201(dynamodb_table):
# π‘ Import the handler AFTER the mock is active so its boto3
# client is intercepted by moto.
from hello_world.app import lambda_handler
event = {
"httpMethod": "POST",
"path": "/orders",
"body": json.dumps({
"customerId": "CUST-001",
"items": [{"productId": "PROD-A", "quantity": 2}],
}),
}
result = lambda_handler(event, None)
assert result["statusCode"] == 201
body = json.loads(result["body"])
assert body["status"] == "created"
assert body["orderId"].startswith("ORD-")
def test_get_missing_order_returns_404(dynamodb_table):
from hello_world.app import lambda_handler
event = {
"httpMethod": "GET",
"path": "/orders/DOESNOTEXIST",
"pathParameters": {"orderId": "DOESNOTEXIST"},
}
result = lambda_handler(event, None)
assert result["statusCode"] == 404
Enter fullscreen mode Exit fullscreen mode
Step 15: Run the tests
python -m pytest tests/unit/ -v
Enter fullscreen mode Exit fullscreen mode
Expected Result: both tests pass with no real AWS calls.
π‘ Unit vs Integration: these moto tests are unit tests (fast, isolated, mocked). The
Invoke-RestMethodcalls againststart-apiin Step 9 hit real DynamoDB, closer to integration tests. The difference: mock for unit tests, real deployed resources for integration tests.
Step 16: Deploy and Run Integration Tests Against a Real Stage
π‘ Unit Tests (moto) prove your logic. Integration Tests prove the whole stack works (API Gateway, Lambda, and DynamoDB together) against a real deployed environment.
sam deploy --guided
Enter fullscreen mode Exit fullscreen mode
π‘
sam deployprovisions real infrastructure via CloudFormation: the Lambda, the API Gateway stage, IAM roles, and the event mappings. Unlikesam local, this creates resources that cost money and must be cleaned up.
Step 17: When it finishes, copy the API Gateway endpoint URL from the Outputs. It looks like:
https://abc123.execute-api.us-east-1.amazonaws.com/Prod/
β οΈ Note the stage is
Prod(SAM’s default), so your full path is.../Prod/orders.
Step 18: Run integration tests against the deployed stage
Create tests/integration/test_api.py:
import os
import requests
# π‘ Pass the deployed URL via an environment variable so the same tests
# can run against dev, staging, or prod without code changes.
BASE_URL = os.environ["API_URL"].rstrip("/")
def test_create_and_get_order():
# Create
create = requests.post(f"{BASE_URL}/orders", json={
"customerId": "CUST-TEST-001",
"items": [{"productId": "PROD-A", "quantity": 1}],
})
assert create.status_code == 201
order_id = create.json()["orderId"]
# Retrieve the same order
get = requests.get(f"{BASE_URL}/orders/{order_id}")
assert get.status_code == 200
assert get.json()["orderId"] == order_id
def test_missing_order_returns_404():
resp = requests.get(f"{BASE_URL}/orders/DOESNOTEXIST")
assert resp.status_code == 404
Enter fullscreen mode Exit fullscreen mode
Step 19: Install requests and run the tests, passing your real URL:
pip install requests
$env:API_URL = "https://abc123.execute-api.us-east-1.amazonaws.com/Prod"
python -m pytest tests/integration/ -v
Enter fullscreen mode Exit fullscreen mode
Expected Result: both tests pass against live AWS.
π‘ Testing pyramid in action. Many fast unit tests (moto), fewer integration tests (deployed stage), fewest end-to-end tests. Integration tests catch problems mocks can’t: IAM permissions, API Gateway mapping, real DynamoDB behaviour.
Step 20: Test an Event-Driven Flow with EventBridge
Not everything is an API. Let’s test an event-driven path using the EventBridge console.
Create a rule and target (console)
Step 20.1 Open the EventBridge console β Rules β Create rule
Step 20.2: Define rule detail
-
Name:
order-placed-rule -
Event bus:
default
Click Next
Step 20.3: Build event pattern
-
Event source:
Other - Creation method: Custom pattern (JSON editor).
- Paste:
{
"source": ["orders.api"],
"detail-type": ["OrderPlaced"]
}
Enter fullscreen mode Exit fullscreen mode
Click Next
Step 20.4: Select target(s)
- Target: AWS service β Lambda function
-
Target location:
Target in this current account -
Function:
testing-toolkit-HelloWorldFunction...
Click Next β Next
Step 20.5: Click Create rule
Step 21: Send a test event
Step 21.1 EventBridge console β Event buses β default β Send events
Step 21.2 Send events
-
Event source:
orders.api -
Detail type:
OrderPlaced - **Event detail:
{ "orderId": "ORD-EVT-001", "customerId": "CUST-EVT", "items": [] }
Enter fullscreen mode Exit fullscreen mode
Click Send
Step 22: Verify it was delivered
Open the Lambda function β Monitor β View CloudWatch logs β newest log stream. You’ll see the event was received.
π‘ Event pattern matching is exact by default.
sourceanddetail-typemust match precisely. Content-based filtering (prefix, numeric,exists) can match ondetailfields. Sending test events from the console is the fastest way to validate rules.β οΈ Our handler expects an API Gateway event shape, so it’ll log the EventBridge event and likely return the default message. That’s fine. The point here is proving the rule β target delivery, not the handler’s response.
Step 23: Generate Realistic Test Events with SAM
Hand-writing event JSON is error-prone. sam local generate-event produces the exact structure AWS services send.
# API Gateway POST event
sam local generate-event apigateway aws-proxy --method POST --path /orders --body '{\"customerId\":\"CUST-001\"}' > events/api_post.json
# S3 object-created event
sam local generate-event s3 put --bucket my-bucket --key orders/data.json > events/s3_put.json
# SQS message event
sam local generate-event sqs receive-message > events/sqs_message.json
# EventBridge (CloudWatch) scheduled event
sam local generate-event cloudwatch scheduled-event > events/scheduled.json
Enter fullscreen mode Exit fullscreen mode
List what’s available:
sam local generate-event --help
sam local generate-event s3 --help
Enter fullscreen mode Exit fullscreen mode
π‘ Generated events include all the metadata (request IDs, ARNs, timestamps) real triggers send, so your local tests behave like production. This is far more reliable than guessing the event shape by hand.
Troubleshooting
Symptom
Cause
Fix
Missing Authentication Token
Path/method not in template Events
Use a declared route; sam build + restart after edits
ResourceNotFoundException
Table missing or wrong region
Create table in the region from env.json & keep regions consistent
Internal server error (500)
Uncaught exception in the function
Read the start-api terminal for the real stack trace
Expecting value: line 1 column 1
JSON file saved with a BOM
Save env.json/event files as UTF-8 without BOM
Binary validation failed for python
Python 3.13 not on PATH
sam build --use-container or install Python 3.13
curl fails in PowerShell
curl is an alias for Invoke-WebRequest
Use Invoke-RestMethod, or curl.exe with a body file
Port 3000 in use
Old start-api still running
Ctrl+C, or kill the PID on port 3000
β οΈ Clean Up Protocol
1 Delete the deployed stack
sam delete --stack-name testing-toolkit --region us-east-1
Enter fullscreen mode Exit fullscreen mode
2 Delete the DynamoDB table
aws dynamodb delete-table --table-name dev-orders --region us-east-1
Enter fullscreen mode Exit fullscreen mode
3 EventBridge β delete order-placed-rule
4 CloudWatch β delete the function’s log groups
5 Remove the local testing-toolkit folder if you’re done
π‘
sam deletetears down the whole CloudFormation stack, so you don’t have to hunt for individual resources. The manually-created DynamoDB table isn’t part of the stack, so delete it separately.**
ποΈ What You Built | π Exam Concepts Recap
What You Built Exam Concept Created the table before invoking SAM local calls real AWS, it does not mock services Pinned region inenv.json and every command
Region consistency across credentials, resources, and config
Declared routes in the template Events
API Gateway routing is configuration, not code
Used DynamoDBCrudPolicy
SAM policy templates for least privilege
sam local invoke with an event file
Direct function testing, bypassing API Gateway
sam local start-api + HTTP calls
Local API Gateway emulation (integration-style)
Wrapped the handler in try/except
Uncaught errors surface as generic 500s
moto @mock_aws unit tests
Mocking AWS in memory for fast, isolated unit tests
Imported the handler after the mock
moto must be active before boto3 clients are created
sam deploy --guided + integration tests
Testing against real deployed resources
Passed the API URL via $env:API_URL
Same tests run against any environment
EventBridge rule + test event
Validating event-driven delivery and pattern matching
sam local generate-event
Realistic event payloads for S3, SQS, API GW, etc.
sam delete for teardown
CloudFormation stack removal
Recognised “Missing Authentication Token”
Generic API Gateway “no matching route” message
Additional Resources
- Test your serverless application with AWS SAM
- Moto: Mock AWS Servicesο
- How to test serverless functions and applications
- AWS SAM policy templates
- Lambda proxy integrations in API Gateway
ποΈ
λ΅κΈ λ¨κΈ°κΈ°