When unit testing functions that access AWS resources, the easiest way is to use the moto library. For instance, I have to test several functions that access an SQS queue, so I proceed this way:
import boto3
from moto import mock_sqs
def create_queue():
client = boto3.client("sqs")
queue_url = client.create_queue(QueueName="queue")["QueueUrl"]
sqs = boto3.resource("sqs")
return sqs.Queue(queue_url)
@mock_sqs
def test_something()
queue = create_queue()
...
Since I had this create_queue() call at the beginning of most of my test functions, I wanted to make it a fixture. So i tried this way:
import boto3
from moto import mock_sqs
from pytest import fixture
@fixture
@mock_sqs
def queue():
client = boto3.client("sqs")
queue_url = client.create_queue(QueueName="queue")["QueueUrl"]
sqs = boto3.resource("sqs")
return sqs.Queue(queue_url)
@mock_sqs
def test_something(queue)
...
Unfortunately, this raised an error in my test functions stating that the queue does not exist. The reason for it is that the decorator @mock_sqs on the fixture would destroy my SQS queue as soon as it would leave the queue() method.
The solution is simple: do not use the mock as a decorator, but trigger it when the fixture is initializing and destroy it when it terminates. That means using a yield within the fixture to return the queue:
import boto3
from moto import mock_sqs
from pytest import fixture
@fixture
def queue():
mock_sqs().start()
client = boto3.client("sqs")
queue_url = client.create_queue(QueueName="queue")["QueueUrl"]
sqs = boto3.resource("sqs")
yield sqs.Queue(queue_url)
mock_sqs().stop()
def test_something(queue)
...
Notice that we have to drop the decorator on the test function as well.
Thanks for the answers to this moto issue.