Testing Serverless Applications — Lambda, Cloud Functions & Local Emulators Guide
In this tutorial, you'll learn about Testing Serverless Applications. We cover key concepts, practical examples, and best practices.
Serverless applications require a different testing approach because you cannot control the runtime environment — the cloud provider manages infrastructure, scaling, and execution context. In this guide, you will learn how to test serverless functions locally using emulators, validate event-driven triggers with mock event payloads, and build CI/CD pipelines that deploy and verify serverless applications automatically. Doda Browser's image processing pipeline uses AWS Lambda for thumbnail generation, and every function goes through local emulator tests before deployment.
Learning Path
flowchart LR A[Cloud Computing Basics] --> B[Serverless Concepts] B --> C[Testing Serverless
You are here] C --> D[CI/CD for Serverless] D --> E[Production Monitoring] style C fill:#f90,color:#fff
Local Testing with SAM CLI (AWS)
AWS SAM CLI provides a local Lambda emulator:
# Install SAM CLI
pip install aws-sam-cli
# Initialize a serverless app
sam init --runtime python3.12 --name thumbnail-service
# Invoke function locally
sam local invoke ThumbnailFunction \
-e events/s3-upload.json \
--env-vars env.json
{
"Records": [
{
"s3": {
"bucket": { "name": "uploads" },
"object": { "key": "photos/photo.jpg" }
}
}
]
}
Writing Serverless Function Tests
Test your handler function directly with mocked event objects:
import json, pytest
from unittest.mock import Mock, patch
def lambda_handler(event, context):
bucket = event["Records"][0]["s3"]["bucket"]["name"]
key = event["Records"][0]["s3"]["object"]["key"]
return {
"statusCode": 200,
"body": json.dumps({"bucket": bucket, "key": key, "processed": True})
}
def test_lambda_handler():
event = {
"Records": [{
"s3": {
"bucket": {"name": "test-bucket"},
"object": {"key": "test-file.jpg"}
}
}]
}
result = lambda_handler(event, Mock())
body = json.loads(result["body"])
assert result["statusCode"] == 200
assert body["bucket"] == "test-bucket"
assert body["processed"] is True
print("Lambda handler test passed")
test_lambda_handler()
Expected output:
Lambda handler test passed
Testing Cloud Functions (GCP)
Google Cloud Functions can be tested with the Functions Framework:
import requests, subprocess, time, os
def hello_world(request):
name = request.args.get("name", "World")
return f"Hello {name}!"
# Using Functions Framework for local testing
def test_cloud_function():
proc = subprocess.Popen(
["functions-framework", "--target", "hello_world", "--port", "8080"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
time.sleep(2)
try:
r = requests.get("http://localhost:8080?name=Alice")
assert r.status_code == 200
assert r.text == "Hello Alice!"
print("Cloud Function test passed")
finally:
proc.terminate()
test_cloud_function()
Testing Event-Driven Triggers
Serverless functions often respond to events like database changes or queue messages:
import json
def process_order_event(event, context):
for record in event["Records"]:
body = json.loads(record["body"])
order_id = body["order_id"]
amount = body["amount"]
if amount <= 0:
raise ValueError(f"Invalid order amount: {amount}")
return {"processed": len(event["Records"])}
def test_valid_order():
event = {
"Records": [
{"body": json.dumps({"order_id": "ORD-001", "amount": 99.99})},
{"body": json.dumps({"order_id": "ORD-002", "amount": 149.99})}
]
}
result = process_order_event(event, None)
assert result["processed"] == 2
print("Valid order test passed")
def test_invalid_order():
event = {
"Records": [
{"body": json.dumps({"order_id": "ORD-003", "amount": -5})}
]
}
try:
process_order_event(event, None)
assert False, "Should have raised ValueError"
except ValueError:
print("Invalid order correctly rejected")
test_valid_order()
test_invalid_order()
Expected output:
Valid order test passed
Invalid order correctly rejected
Cold Start Testing
Measure cold start latency by forcing fresh execution contexts:
import time, requests, json
def measure_cold_start():
url = "https://your-lambda-url.execute-api.region.amazonaws.com/dev/hello"
timings = []
for i in range(5):
start = time.time()
r = requests.get(url)
elapsed = (time.time() - start) * 1000
timings.append(elapsed)
time.sleep(1)
print(f"Cold starts (ms): min={min(timings):.0f}, "
f"max={max(timings):.0f}, avg={sum(timings)/len(timings):.0f}")
measure_cold_start()
Serverless CI/CD Testing Pipeline
name: Serverless Tests
on: [push]
jobs:
test-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install -r requirements.txt aws-sam-cli
- name: Run unit tests
run: pytest tests/
- name: Invoke locally
run: sam local invoke MyFunction -e events/test-event.json
- name: Deploy
run: sam deploy --no-confirm-changeset --no-fail-on-empty-changeset
Practice Questions
1. What is the main challenge in testing serverless functions?
You cannot control the runtime environment. Testing must happen locally with emulators before deployment.
2. How does SAM CLI help with local Lambda testing?
SAM CLI provides a local emulator that mimics the Lambda runtime environment, allowing you to invoke functions with event payloads.
3. What is a cold start and why should you test for it?
A cold start occurs when a new execution context is created, adding latency. Testing cold starts helps you set appropriate timeout values and optimize function size.
4. How do you test event-driven functions?
Mock the event payload and invoke the handler function directly. Test multiple event shapes including edge cases like empty records or malformed payloads.
Challenge: Build a serverless image resizing function that responds to S3 upload events. Write unit tests, local emulator tests, and a CI/CD pipeline. Test: valid image processing, unsupported format rejection, file size limits, and concurrent uploads.
FAQ
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro