Skip to content

Testing Serverless Applications — Lambda, Cloud Functions & Local Emulators Guide

DodaTech Updated 2026-06-24 4 min read

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 is serverless testing?

Serverless testing validates cloud functions (Lambda, Cloud Functions) by running them locally with emulators, testing event triggers, and verifying deployment configurations.

How do I test serverless functions without cloud costs?

Use local emulators like SAM CLI, Functions Framework, or LocalStack to run functions entirely offline.

What is the difference between testing serverless and containerized apps?

Serverless functions are stateless and event-driven. Container testing focuses on the runtime environment; serverless testing focuses on the handler logic and event shapes.

How do I test function permissions and IAM roles?

Use infrastructure-as-code testing tools like aws-iam-validator or deploy to a sandbox environment and run integration tests.

What's Next

Testing GraphQL APIs
Testing Kubernetes Apps
CI/CD Testing Pipeline

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro