AWS SDK Testing Basics
Seven examples to get you started testing AWS SDK code - five basic and two intermediate.
Busque em todas as páginas da documentação
Seven examples to get you started testing AWS SDK code - five basic and two intermediate.
Each example mocks the same kind of call in both Python (moto) and TypeScript (aws-sdk-client-mock), so you can see the equivalent pattern side by side.
pip install moto[s3] pytest (moto 5.x, boto3 1.43.x, Python 3.10+).npm install --save-dev aws-sdk-client-mock vitest (or Jest; Node.js 18+).The simplest test: mock one operation and assert on the result.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
@mock_aws
def test_bucket_exists_after_create():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="my-test-bucket")
response = s3.list_buckets()
names = [b["Name"] for b in response["Buckets"]]
assert "my-test-bucket" in names// --- TypeScript (AWS SDK v3) ---
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
import { mockClient } from "aws-sdk-client-mock";
import { sdkStreamMixin } from "@aws-sdk/util-stream-node";
import { Readable } from "node:stream";
const s3Mock = mockClient(S3Client);
test("reads an object body", async () => {
const stream = sdkStreamMixin(Readable.from(["hello world"]));
s3Mock.on(GetObjectCommand).resolves({ Body: stream as never });
const s3 = new S3Client({});
const res = await s3.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
expect(await res.Body!.transformToString()).toBe("hello world");
});@mock_aws intercepts every boto3 call made inside the decorated function.mockClient(S3Client) returns a stand-in you configure per command with .on(...).resolves(...).Related: Why AWS SDK Code Needs Its Own Testing Strategy - the boundary these mocks patch.
Most tests need existing data in place before the code under test runs.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
@mock_aws
def test_reads_seeded_object():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="reports")
s3.put_object(Bucket="reports", Key="q1.csv", Body=b"revenue,1000")
obj = s3.get_object(Bucket="reports", Key="q1.csv")
assert obj["Body"].read() == b"revenue,1000"// --- TypeScript (AWS SDK v3) ---
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
import { mockClient } from "aws-sdk-client-mock";
const ddbMock = mockClient(DynamoDBClient);
test("reads a seeded item", async () => {
ddbMock.on(GetItemCommand, { TableName: "Orders", Key: { id: { S: "o-1" } } })
.resolves({ Item: { id: { S: "o-1" }, total: { N: "42" } } });
const ddb = new DynamoDBClient({});
const res = await ddb.send(new GetItemCommand({ TableName: "Orders", Key: { id: { S: "o-1" } } }));
expect(res.Item?.total.N).toBe("42");
});create_bucket, put_object) - moto stores it in-memory.aws-sdk-client-mock takes a match argument on .on(Command, input) to stub a response only for a specific input.Wrap the client in your own function and test that function's behavior.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
def object_size(bucket: str, key: str) -> int:
s3 = boto3.client("s3")
return s3.head_object(Bucket=bucket, Key=key)["ContentLength"]
@mock_aws
def test_object_size():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="reports")
s3.put_object(Bucket="reports", Key="q1.csv", Body=b"12345")
assert object_size("reports", "q1.csv") == 5// --- TypeScript (AWS SDK v3) ---
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
import { mockClient } from "aws-sdk-client-mock";
async function objectSize(s3: S3Client, bucket: string, key: string): Promise<number> {
const head = await s3.send(new HeadObjectCommand({ Bucket: bucket, Key: key }));
return head.ContentLength ?? 0;
}
const s3Mock = mockClient(S3Client);
test("objectSize reads ContentLength", async () => {
s3Mock.on(HeadObjectCommand).resolves({ ContentLength: 5 });
const size = await objectSize(new S3Client({}), "reports", "q1.csv");
expect(size).toBe(5);
});objectSize (dependency injection) makes it trivial to substitute the mocked client in tests.Test that your code handles a specific AWS error correctly.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
from botocore.exceptions import ClientError
@mock_aws
def test_missing_key_raises_not_found():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="reports")
try:
s3.get_object(Bucket="reports", Key="missing.csv")
assert False, "expected ClientError"
except ClientError as err:
assert err.response["Error"]["Code"] == "NoSuchKey"// --- TypeScript (AWS SDK v3) ---
import { S3Client, GetObjectCommand, NoSuchKey } from "@aws-sdk/client-s3";
import { mockClient } from "aws-sdk-client-mock";
const s3Mock = mockClient(S3Client);
test("missing key rejects with NoSuchKey", async () => {
s3Mock.on(GetObjectCommand).rejects(new NoSuchKey({ message: "not found", $metadata: {} }));
const s3 = new S3Client({});
await expect(s3.send(new GetObjectCommand({ Bucket: "b", Key: "missing.csv" })))
.rejects.toBeInstanceOf(NoSuchKey);
});ClientError your code would see against real S3 for an unknown key..rejects(...) on aws-sdk-client-mock lets you simulate a specific typed SDK error.Stale stubs from one test can silently pass a later one; reset between tests.
# --- Python (boto3) ---
# moto's @mock_aws creates a fresh, isolated mock backend per decorated
# test function - nothing to reset by hand.
from moto import mock_aws
@mock_aws
def test_a():
...
@mock_aws
def test_b():
... # starts with a clean, empty mock backend// --- TypeScript (AWS SDK v3) ---
import { S3Client } from "@aws-sdk/client-s3";
import { mockClient } from "aws-sdk-client-mock";
const s3Mock = mockClient(S3Client);
beforeEach(() => {
s3Mock.reset(); // clears configured stubs and call history
});aws-sdk-client-mock instances are module-level, so you must call .reset() in a beforeEach or stubs leak across tests..reset() is the most common aws-sdk-client-mock bug - a later test unexpectedly reuses an earlier stub.Sometimes the important thing is what your code sent, not what it got back.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
@mock_aws
def test_put_object_sets_content_type():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="reports")
s3.put_object(Bucket="reports", Key="q1.json", Body=b"{}", ContentType="application/json")
head = s3.head_object(Bucket="reports", Key="q1.json")
assert head["ContentType"] == "application/json"// --- TypeScript (AWS SDK v3) ---
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
import { mockClient } from "aws-sdk-client-mock";
const ddbMock = mockClient(DynamoDBClient);
test("writes the expected item shape", async () => {
ddbMock.on(PutItemCommand).resolves({});
const ddb = new DynamoDBClient({});
await ddb.send(new PutItemCommand({ TableName: "Orders", Item: { id: { S: "o-1" } } }));
expect(ddbMock).toHaveReceivedCommandWith(PutItemCommand, {
TableName: "Orders",
Item: { id: { S: "o-1" } },
});
});head_object) verifies your code's write had the intended real effect.aws-sdk-client-mock's toHaveReceivedCommandWith matcher asserts on the exact input your code sent.Real code often makes more than one SDK call in sequence; test the whole flow.
# --- Python (boto3) ---
import boto3
from moto import mock_aws
def archive_report(bucket: str, key: str) -> None:
s3 = boto3.client("s3")
s3.copy_object(Bucket=bucket, CopySource=f"{bucket}/{key}", Key=f"archive/{key}")
s3.delete_object(Bucket=bucket, Key=key)
@mock_aws
def test_archive_report_moves_object():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="reports")
s3.put_object(Bucket="reports", Key="q1.csv", Body=b"data")
archive_report("reports", "q1.csv")
keys = [o["Key"] for o in s3.list_objects_v2(Bucket="reports")["Contents"]]
assert keys == ["archive/q1.csv"]// --- TypeScript (AWS SDK v3) ---
import { S3Client, CopyObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
import { mockClient } from "aws-sdk-client-mock";
async function archiveReport(s3: S3Client, bucket: string, key: string): Promise<void> {
await s3.send(new CopyObjectCommand({ Bucket: bucket, CopySource: `${bucket}/${key}`, Key: `archive/${key}` }));
await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
}
const s3Mock = mockClient(S3Client);
test("archiveReport copies then deletes", async () => {
s3Mock.on(CopyObjectCommand).resolves({});
s3Mock.on(DeleteObjectCommand).resolves({});
await archiveReport(new S3Client({}), "reports", "q1.csv");
expect(s3Mock).toHaveReceivedCommandTimes(CopyObjectCommand, 1);
expect(s3Mock).toHaveReceivedCommandTimes(DeleteObjectCommand, 1);
});Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última atualização: 23 de jul. de 2026