I have a Flask app that uses AWS services such as dynamodb. I want to mock these out during unit tests but I’m having trouble doing so.
Here is a minimal example that doesn’t work for me:
JavaScript
x
31
31
1
from flask import Flask
2
import boto3
3
4
app = Flask(__name__)
5
6
@app.route("/")
7
def hello():
8
aws_session = boto3.session.Session()
9
dynamodb = aws_session.resource("dynamodb")
10
table = dynamodb.Table("test-table")
11
table.put_item(Item={
12
"hello": "world"
13
})
14
return "ok"
15
16
17
from moto import mock_dynamodb
18
import pytest
19
20
21
@pytest.fixture
22
def client():
23
with app.test_client() as client:
24
yield client
25
26
27
@mock_dynamodb
28
def test_response(client):
29
rv = client.get('/')
30
assert rv.data == "ok"
31
I’m getting an error that the resource does not exist. This means that an AWS call is in fact being made. Why isn’t the call mocked out?
Advertisement
Answer
Moto acts more as a emulator than a traditional mock. It emulates the happy path, but it will also throw the same errors that AWS would if there is anything wrong with the input.
AWS would throw an error here that the table does not exist – so Moto does the same. (And, like AWS, Moto actually needs the table to exist before it can ‘persist’ the item in there.)
The request is mocked successfully when creating the table first:
JavaScript
1
17
17
1
@app.route("/")
2
def hello():
3
aws_session = boto3.session.Session()
4
conn = aws_session.client("dynamodb")
5
conn.create_table(
6
TableName="test-table",
7
KeySchema=[{"AttributeName": "hello", "KeyType": "HASH"}],
8
AttributeDefinitions=[{"AttributeName": "hello", "AttributeType": "S"}],
9
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
10
)
11
dynamodb = aws_session.resource("dynamodb")
12
table = dynamodb.Table("test-table")
13
table.put_item(Item={
14
"hello": "world"
15
})
16
return "ok"
17