45 / 75 · 08 Infrastructure as Code Testing · Serverless Function Testing← prev⊞ allnext →☰ Read as one page
8.4Serverless Testing Challenges and Solutions
| Challenge | Solution | Tool/Approach |
|---|---|---|
| Cold start latency | Measure p99 latency in load tests | Artillery, k6 with Lambda targets |
| Timeout behavior | Set function timeout lower than test timeout | SAM template Timeout property |
| Memory limits | Profile memory usage at expected payload sizes | Lambda Power Tuning |
| Concurrency limits | Load test with reserved concurrency | k6 with ramp-up scenarios |
| IAM permissions | Test with least-privilege role locally | SAM local with credential profiles |
| Event source mapping | Test with realistic event payloads | Event replay from CloudWatch |
| Idempotency | Send duplicate events, verify no double-processing | Integration tests with retry logic |
Cold Start Testing
# tests/performance/test_cold_start.py
import time
import boto3
import statistics
def measure_cold_start(function_name, num_invocations=10):
"""Measure cold start latency by forcing new execution environments."""
client = boto3.client("lambda")
latencies = []
for i in range(num_invocations):
# Update environment variable to force a new container
client.update_function_configuration(
FunctionName=function_name,
Environment={
"Variables": {
"COLD_START_TRIGGER": str(time.time())
}
}
)
# Wait for update to propagate
time.sleep(5)
start = time.time()
response = client.invoke(
FunctionName=function_name,
Payload=b'{"test": true}',
)
elapsed_ms = (time.time() - start) * 1000
latencies.append(elapsed_ms)
return {
"p50": statistics.median(latencies),
"p95": sorted(latencies)[int(len(latencies) * 0.95)],
"p99": sorted(latencies)[int(len(latencies) * 0.99)],
"max": max(latencies),
}
Timeout Testing
def test_function_completes_before_timeout():
"""Verify the function completes within its configured timeout."""
import time
FUNCTION_TIMEOUT = 30 # seconds (from SAM template)
SAFETY_MARGIN = 5 # seconds
start = time.time()
result = lambda_handler(large_event, context)
elapsed = time.time() - start
assert elapsed < (FUNCTION_TIMEOUT - SAFETY_MARGIN), \
f"Function took {elapsed:.1f}s, dangerously close to {FUNCTION_TIMEOUT}s timeout"