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:
from flask import Flask
import boto3
app = Flask(__name__)
@app.route("/")
def hello():
aws_session = boto3.session.Session()
dynamodb = aws_session.resource("dynamodb")
table = dynamodb.Table("test-table")
table.put_item(Item={
"hello": "world"
})
return "ok"
from moto import mock_dynamodb
import pytest
@pytest.fixture
def client():
with app.test_client() as client:
yield client
@mock_dynamodb
def test_response(client):
rv = client.get('/')
assert rv.data == "ok"
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?
CodePudding user response:
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:
@app.route("/")
def hello():
aws_session = boto3.session.Session()
conn = aws_session.client("dynamodb")
conn.create_table(
TableName="test-table",
KeySchema=[{"AttributeName": "hello", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "hello", "AttributeType": "S"}],
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
)
dynamodb = aws_session.resource("dynamodb")
table = dynamodb.Table("test-table")
table.put_item(Item={
"hello": "world"
})
return "ok"