SAM Local Testing
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
SAM Local Testing: A Deep Dive into Serverless Development
Introduction: Why Local Testing Matters in Serverless
When you start building applications with AWS Serverless Application Model (SAM), you are essentially shifting your development paradigm from traditional server-based architectures to event-driven, managed services. In a traditional environment, you might have a local staging server that mimics production. In serverless, however, your "server" is an abstraction provided by AWS services like Lambda, API Gateway, and DynamoDB. Testing these locally presents a unique challenge: how do you verify your code without deploying it to the cloud every single time?
This is where SAM Local testing enters the picture. The AWS SAM CLI provides a suite of tools that allow you to emulate the AWS environment on your local machine. By using Docker containers that mimic the execution environment of AWS Lambda, you can run your code, debug it, and inspect its behavior before you ever trigger a deployment. This workflow is critical for maintaining productivity, reducing costs associated with repeated deployments, and shortening the feedback loop between writing code and verifying functionality.
Without a local testing strategy, developers often fall into the "deploy-test-fix" cycle. This involves pushing code to the cloud, waiting for the deployment to complete, checking logs in CloudWatch, and then repeating the process. This cycle is notoriously slow and frustrating. By mastering SAM local testing, you reclaim control over your development time and build a more reliable, test-driven development process.
Understanding the SAM CLI Architecture
The AWS SAM CLI is built around the concept of "emulation." It does not recreate the entire AWS ecosystem on your laptop; rather, it uses Docker to create an environment that matches the runtime settings of your Lambda functions. When you invoke a function locally, SAM pulls the appropriate Docker image (e.g., Python 3.9, Node.js 18, Java 11) and runs your code inside that container, injecting mock event data as if it were coming from an actual AWS trigger.
Key Components of SAM Local
To effectively use SAM for local testing, you need to understand three primary commands:
sam local invoke: Executes a single Lambda function locally with a specific event payload.sam local start-api: Starts a local web server that mimics API Gateway, allowing you to trigger functions via HTTP requests.sam local start-lambda: Starts a local endpoint that mimics the AWS Lambda service, which can be used to test service-to-service communication.
Callout: The "Local vs. Cloud" Distinction While SAM local is excellent for testing logic, input validation, and code structure, it is not a perfect mirror of the cloud. Local testing cannot replicate IAM permissions, service quotas, or real-world network latency. Always treat local testing as the first line of defense, but never skip integration testing in a real AWS environment before going to production.
Setting Up Your Development Environment
Before you can run local tests, you must ensure your workstation is configured correctly. The primary requirement for SAM local testing is Docker. Because SAM uses containers to emulate the Lambda execution environment, the Docker daemon must be running and accessible by the SAM CLI.
Prerequisites
- AWS SAM CLI: Installed and configured.
- Docker Desktop (or Docker Engine): Running on your machine.
- AWS CLI: Configured with valid credentials (even if you are only running locally, SAM often needs credentials to resolve environment variables or access local configuration).
Verification Steps
To verify that your installation is ready, open your terminal and run the following commands:
- Check SAM CLI version:
sam --version - Check Docker availability:
docker ps
If these commands return successfully, your environment is ready. If Docker fails, ensure your Docker Desktop application is fully launched and your user account has the necessary permissions to interact with the Docker socket.
Mastering sam local invoke
sam local invoke is the bread and butter of unit testing your Lambda functions. It allows you to pass a JSON file representing an event (like an S3 upload or a DynamoDB change) to your function and see the output immediately.
The Workflow
- Write your function code: Create your Lambda handler.
- Create an event file: Create a
events/event.jsonfile containing the mock data you expect your function to process. - Run the invoke command: Execute
sam local invoke FunctionName -e events/event.json.
Practical Example: Processing an API Gateway Event
Imagine you have a function that processes a POST request. Your events/event.json should look like a standard API Gateway proxy request:
{
"resource": "/my-path",
"path": "/my-path",
"httpMethod": "POST",
"body": "{\"name\": \"John Doe\", \"action\": \"create\"}",
"headers": {
"Content-Type": "application/json"
}
}
Now, run the command:
sam local invoke MyFunction --event events/event.json
SAM will pull the necessary Docker image, mount your code directory into the container, and execute the function. You will see the function's logs stream to your terminal, followed by the JSON output returned by your code.
Tip: Debugging with Environment Variables Often, your code relies on environment variables (e.g.,
TABLE_NAME,DEBUG_MODE). You can pass these tosam local invokeusing the--env-varsflag. Create a JSON file (e.g.,env.json) to define these variables and use the command:sam local invoke MyFunction -e events/event.json --env-vars env.json.
Simulating APIs with sam local start-api
Testing individual functions is great, but testing the interaction between your API Gateway routes and your Lambda functions is better. The sam local start-api command creates a local HTTP server that routes requests to your Lambda functions based on your template.yaml configuration.
How it works
When you run sam local start-api, SAM reads your template.yaml file, parses the AWS::Serverless::Function and Events properties, and maps them to local ports. If your API is defined on port 3000, you can point your browser or tools like Postman or curl to http://localhost:3000/.
Step-by-Step Implementation
- Ensure your
template.yamldefines anApievent source for your function. - Run
sam local start-apiin your project root. - Once the server is running, open a new terminal window.
- Send a request:
curl -X POST http://localhost:3000/my-path -d '{"data": "test"}'.
This allows you to test your middleware, validation logic, and response formatting in a way that feels very similar to hitting a live API.
Callout: Performance and Hot Reloading One of the most powerful features of
sam local start-apiis its ability to handle code changes. If you are using interpreted languages like Python or Node.js, SAM will automatically re-mount your code changes on each request if you are running in a standard configuration. This enables a "hot-reloading" experience where you change a line of code, save the file, and immediately hit the API to see the results.
Advanced Testing Techniques
As your application grows, simple invocation is not enough. You need to handle complexities like secrets, layers, and service emulation.
Testing with Lambda Layers
If your project uses Lambda Layers to share code or dependencies, SAM handles this by mounting the layer directory into the container alongside your function code. You don't need to do anything special; just ensure your template.yaml references the layer correctly. SAM will look for the layer files in your local project directory and make them available to the runtime.
Mocking AWS Services
SAM Local does not automatically mock services like DynamoDB or SQS. If your code calls boto3.client('dynamodb'), it will attempt to reach the actual AWS DynamoDB endpoint. To test locally without hitting AWS, you have two primary options:
- Use Moto: A Python library that mocks AWS services. You can use it within your unit tests to intercept calls to AWS.
- Use LocalStack: A popular open-source tool that provides a local cloud stack. You can configure your SAM functions to point to the LocalStack endpoint instead of the real AWS endpoint by setting the
ENDPOINT_OVERRIDEenvironment variable.
Handling IAM Permissions
A common pitfall is assuming that because your code runs locally, it has the same permissions as your deployed function. This is false. When running locally, SAM uses your local machine's AWS credentials (usually defined in ~/.aws/credentials). If your local user has administrator access, your local function will have administrator access, even if the actual Lambda role is restricted. Always use a least-privilege policy for your local development profile to catch permission issues early.
Best Practices for SAM Local Testing
1. Maintain a Dedicated Events Library
Do not just keep one event.json file. Create an events/ folder in your project and store different types of events there. For example:
events/api_post_request.jsonevents/s3_upload_event.jsonevents/sqs_message.jsonThis ensures you can test various code paths without manually editing a single file every time.
2. Use Unit Testing Frameworks
SAM Local is an integration/emulation tool, not a substitute for proper unit tests. Use frameworks like pytest (for Python) or Jest (for Node.js) to test your business logic in isolation. Use SAM Local to verify that the "glue" code (the event parsing and the response construction) works correctly.
3. Keep Docker Images Updated
SAM periodically releases new Docker images to match updated Lambda runtimes. Run sam build --use-container periodically to ensure your local environment is pulling the latest images, which contain security patches and updated library environments.
4. Manage Environment Variables Securely
Never commit your env.json or aws-credentials files to version control. Use a .gitignore file to exclude these files. If you need to share environment structures with your team, use a template file like env.json.template and instruct team members to fill in their own values.
Common Pitfalls and Troubleshooting
"My function is timing out locally!"
If your function times out locally, it is often due to the overhead of starting the Docker container. Increase the Timeout property in your template.yaml for testing, or check if your function is trying to establish a connection to a resource (like a database) that isn't accessible from your local network.
"My changes aren't reflecting!"
If you make a change to your code but the output remains the same, you likely haven't rebuilt your project. SAM builds your code into a .aws-sam directory. Whenever you change your code, run sam build before running sam local invoke. If you are using the --use-container flag, this is even more critical as it ensures the build artifacts are compatible with the execution environment.
"The local endpoint is blocked!"
Ensure your firewall or antivirus software isn't blocking the ports SAM uses (default 3000). Also, ensure that no other service on your machine is using the same port. You can change the port for sam local start-api using the -p flag: sam local start-api -p 8080.
Comparison Table: SAM Local vs. Unit Testing vs. Cloud Testing
| Feature | SAM Local | Unit Testing | Cloud Testing |
|---|---|---|---|
| Speed | Medium | Very Fast | Slow |
| Accuracy | High (Emulated) | Low (Logic only) | Perfect (Actual) |
| Infrastructure | Minimal (Docker) | None | Full AWS |
| Cost | Free | Free | Incurring |
| Best For | Integration/Event Flow | Logic/Business Rules | Production Readiness |
Step-by-Step: Testing a Full Workflow
To put everything together, let's walk through testing a simple "Create User" Lambda.
- Initialize the template: Use
sam initto create a standard project structure. - Define the resource: In
template.yaml, add anAWS::Serverless::Functionwith anApievent. - Write the handler: Write the logic to parse the body and save to a mock database.
- Build the project: Run
sam build. - Run the API: Run
sam local start-api. - Test the endpoint: Use
curlto send a POST request tolocalhost:3000. - Inspect logs: Observe the standard output in your terminal where
sam local start-apiis running. - Iterate: If the code fails, update the handler, run
sam buildagain, and retry thecurlcommand.
This cycle is the backbone of efficient serverless development. By keeping the feedback loop tight, you can experiment with different library versions, event structures, and logic flow without the overhead of the AWS Console.
Security Considerations in Local Testing
While testing locally, you are essentially running code in a container that has access to your local machine's credentials. It is vital to recognize that if your code is malicious or poorly written, it could potentially access your local AWS configuration files.
- Restrict IAM Policies: Never use your root account credentials for local development. Use an IAM user with minimal permissions.
- Avoid Hardcoding Secrets: Even in local testing, do not hardcode secrets in your source code. Use environment variables and load them via the
env.jsonfile. - Network Isolation: Be aware that if you are connected to a corporate VPN, your local Lambda container might have access to internal resources that your production Lambda would not. Ensure your tests reflect the intended network environment.
FAQ: Frequently Asked Questions
Can I debug my code with breakpoints while using SAM Local?
Yes. You can use the --debug-port flag with sam local invoke or sam local start-api. This opens a port that your IDE (like VS Code or PyCharm) can attach to, allowing you to set breakpoints, inspect variables, and step through your code just as if it were running on your local machine.
Does SAM Local support all AWS services?
No. SAM Local is primarily designed for Lambda, API Gateway, and SQS/SNS local emulation. For services like Cognito, AppSync, or EventBridge, you might need to use third-party mocks or write custom logic to emulate those events.
Is sam local the same as sam build?
No. sam build prepares your code and dependencies by creating a deployment package. sam local is the execution engine that uses those packages to run your code. You must run sam build before running sam local.
Can I run SAM Local on Windows?
Yes, SAM CLI supports Windows, but you must have Docker Desktop installed with WSL 2 (Windows Subsystem for Linux) integration enabled. This is the recommended way to ensure compatibility between the Linux-based Lambda environment and your Windows development environment.
Key Takeaways
- Shorten the Feedback Loop: The primary goal of SAM Local testing is to avoid the time-consuming deploy-test-fix cycle by emulating the AWS runtime environment on your local machine.
- Leverage Docker: SAM relies on Docker to create a consistent execution environment. A healthy Docker installation is the foundation of a successful local testing workflow.
- Use the Right Tool for the Job: Use
sam local invokefor isolated function testing,sam local start-apifor integration testing of API routes, and traditional unit testing frameworks for business logic. - Maintain an Event Library: Build a robust collection of JSON event files. This allows you to quickly simulate different triggers, such as API requests, S3 uploads, or database stream changes, without manual configuration.
- Debug Effectively: Utilize the
--debug-portflag to attach your IDE debugger to the Lambda container, which provides a significantly better experience than relying solely on print statements. - Mind the Differences: Remember that local testing is an emulation, not a mirror. Always perform final integration tests in a real AWS environment to account for IAM roles, service quotas, and network configuration.
- Security First: Even during development, adhere to the principle of least privilege by using scoped AWS credentials and never committing sensitive information to your local configuration files.
By internalizing these practices, you move from a reactive developer waiting on cloud deployments to a proactive engineer who can verify, debug, and iterate on complex serverless applications with confidence and speed. The transition to serverless does not mean you have to sacrifice the immediate feedback of local development; you simply need to adapt your tooling to the new paradigm of container-based execution.
Continue the course
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons