




























































































Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
For example, we have the following code we want to test: import boto3 class MyModel(object): def __init__(self, name, value): self.name = name.
Typology: Schemes and Mind Maps
1 / 183
This page cannot be seen from the preview
Don't miss anything!





























































































ii
A library that allows you to easily mock out tests based on AWS infrastructure.
ONE
GETTING STARTED
If you’ve never used moto before, you should read the Getting Started with Moto guide to get familiar with moto and its usage.
4 Chapter 1. Getting Started
Decorator
With a decorator wrapping, all the calls to S3 are automatically mocked out.
import boto from moto import mock_s from mymodule import MyModel
@mock_s def test_my_model_save(): conn = boto3.resource('s3', region_name='us-east-1')
conn.create_bucket(Bucket='mybucket')
model_instance = MyModel('steve', 'is awesome') model_instance.save()
body = conn.Object('mybucket', 'steve').get()[ 'Body'].read().decode("utf-8")
assert body == 'is awesome'
Context manager
Same as the Decorator, every call inside the with statement is mocked out.
def test_my_model_save(): with mock_s3(): conn = boto3.resource('s3', region_name='us-east-1') conn.create_bucket(Bucket='mybucket')
model_instance = MyModel('steve', 'is awesome') model_instance.save()
body = conn.Object('mybucket', 'steve').get()[ 'Body'].read().decode("utf-8")
assert body == 'is awesome'
Raw
You can also start and stop the mocking manually.
def test_my_model_save(): mock = mock_s3() mock.start()
conn = boto3.resource('s3', region_name='us-east-1') conn.create_bucket(Bucket='mybucket')
model_instance = MyModel('steve', 'is awesome') (continues on next page)
6 Chapter 2. Additional Resources
(continued from previous page) model_instance.save()
body = conn.Object('mybucket', 'steve').get()[ 'Body'].read().decode("utf-8")
assert body == 'is awesome'
mock.stop()
Unittest usage
If you use unittest to run tests, and you want to use moto inside setUp , you can do it with .start() and .stop() like:
import unittest from moto import mock_s import boto
def func_to_test(bucket_name, key, content): s3 = boto3.resource('s3') object = s3.Object(bucket_name, key) object.put(Body=content)
class MyTest(unittest.TestCase): mock_s3 = mock_s3() bucket_name = 'test-bucket' def setUp(self): self.mock_s3.start()
s3 = boto3.resource('s3') bucket = s3.Bucket(self.bucket_name) bucket.create()
def tearDown(self): self.mock_s3.stop()
def test(self): content = b"abc" key = '/path/to/obj'
func_to_test(self.bucket_name, key, content)
s3 = boto3.resource('s3') object = s3.Object(self.bucket_name, key) actual = object.get()['Body'].read() self.assertEqual(actual, content)
It is possible to use Moto as a class-decorator. Note that this may behave differently then you might expected - it currently creates a global state on class-level, rather than on method-level.
2.1. Getting Started with Moto 7
Example on usage
If you are a user of pytest, you can leverage pytest fixtures to help set up your mocks and other AWS resources that you would need.
Here is an example:
@pytest.fixture(scope='function') def aws_credentials(): """Mocked AWS Credentials for moto.""" os.environ['AWS_ACCESS_KEY_ID'] = 'testing' os.environ['AWS_SECRET_ACCESS_KEY'] = 'testing' os.environ['AWS_SECURITY_TOKEN'] = 'testing' os.environ['AWS_SESSION_TOKEN'] = 'testing'
@pytest.fixture(scope='function') def s3(aws_credentials): with mock_s3(): yield boto3.client('s3', region_name='us-east-1')
In the code sample above, all of the AWS/mocked fixtures take in a parameter of aws_credentials , which sets the proper fake environment variables. The fake environment variables are used so that botocore doesn’t try to locate real credentials on your system.
Next, once you need to do anything with the mocked AWS environment, do something like:
def test_create_bucket(s3):
s3.create_bucket(Bucket="somebucket")
result = s3.list_buckets() assert len(result['Buckets']) == 1 assert result['Buckets'][0]['Name'] == 'somebucket'
What about those pesky imports
Recall earlier, it was mentioned that mocks should be established BEFORE the clients are set up. One way to avoid import issues is to make use of local Python imports – i.e. import the module inside of the unit test you want to run vs. importing at the top of the file.
Example:
def test_something(s3): from some.package.that.does.something.with.s3 import some_func # <-- Local import␣ ˓→for unit test
some_func() # The mock has been established from the "s3" pytest fixture, so this␣ ˓→function that uses
˓→out to AWS.
2.1. Getting Started with Moto 9
Patching the client or resource
If it is not possible to rearrange imports, we can patch the boto3-client or resource after the mock has started. See the following code sample:
client = boto3.client("s3") s3 = boto3.resource("s3")
@mock_s def test_mock_works_with_client_or_resource_created_outside(): from moto.core import patch_client, patch_resource patch_client(outside_client) patch_resource(s3)
assert client.list_buckets()["Buckets"] == []
assert list(s3.buckets.all()) == []
This will ensure that the boto3 requests are still mocked.
Other caveats
For Tox, Travis CI, and other build systems, you might need to also perform a touch ~/.aws/credentials command before running the tests. As long as that file is present (empty preferably) and the environment variables above are set, you should be good to go.
2.2 Non-Python SDK’s / Server Mode
Moto has a stand-alone server mode. This allows you to use Moto with any of the official AWS SDK’s.
Install the required dependencies using:
pip install moto[server]
You can then start it like this:
$ moto_server
You can also pass the port:
$ moto_server -p
If you want to be able to use the server externally you can pass an IP address to bind to as a hostname or allow any of your external interfaces with 0.0.0.0:
$ moto_server -H 0.0.0.
Please be aware this might allow other network users to access your server.
To use Moto in your tests, you can pass the endpoint_url -parameter to the SDK of your choice.
10 Chapter 2. Additional Resources
It is possible to call the MotoServer for tests that were written using decorators. The following environment variables can be set to achieve this:
TEST_SERVER_MODE=true
Whenever a mock-decorator starts, Moto will:
Calling the reset-API ensures the same behaviour as normal decorators, where the complete state is removed. It is possible to keep the state in between tests, using this environment variable:
MOTO_CALL_RESET_API=true
Moto comes with a dashboard to view the current state of the system:
http://localhost:5000/moto-api/
An internal API endpoint is provided to reset the state of all of the backends. This will remove all S3 buckets, EC servers, etc.:
requests.post("http://motoapi.amazonaws.com/moto-api/reset")
Moto is also available to install using Homebrew, which makes it much easier to manage if you’re not using Python as your primary development language.
Once Homebrew is installed, you can install Moto by running:
brew install moto
To make the Moto server start up automatically when you log into your computer, you can run:
brew services start moto
12 Chapter 2. Additional Resources
The standalone server has some caveats with some services. The following services require that you update your hosts file for your code to work properly:
For the above services, this is required because the hostname is in the form of AWS_ACCOUNT_ID.localhost. As a result, you need to add that entry to your host file for your tests to function properly.
2.3 FAQ
No. Moto is not designed for multithreaded access/multiprocessing.
Moto has a dependency on the pip-module cryptography. As of Cryptography >= 3.4, this module requires Rust as a dependency. Most OS/platforms will support the installation of Rust, but if you’re getting any errors related to this, see the cryptography documentation for more information: https://cryptography.io/en/latest/installation/#rust
2.4 Boto vs Boto
Boto3 is the latest Python SDK, and as such the SDK targeted by Moto. All our @mock_ -decorators should be usable against any boto3-version.
Still stuck on boto, the former SDK? Moto does have some support, in the form of our deprecated services:
from moto import mock_ec2_deprecated import boto
@mock_ec2_deprecated def test_something_with_ec2(): ec2_conn = boto.ec2.connect_to_region('us-east-1') ec2_conn.get_only_instances(instance_ids='i-123456')
When using both boto2 and boto3, one can do this to avoid confusion:
from moto import mock_ec2_deprecated as mock_ec2_b from moto import mock_ec
If you want to use Server Mode, the easiest way is to create a boto config file ( ~/.boto ) with the following values:
[Boto] is_secure = False https_validate_certificates = False proxy_port = 5000 proxy = 127.0.0.
2.6 AWS Config Support
An experimental feature for AWS Config has been developed to provide AWS Config capabilities in your unit tests. This feature is experimental as there are many services that are not yet supported and will require the community to add them in over time. This page details how the feature works and how you can use it.
AWS Config is an AWS service that describes your AWS resource types and can track their changes over time. At this time, moto does not have support for handling the configuration history changes, but it does have a few methods mocked out that can be immensely useful for unit testing.
If you are developing automation that needs to pull against AWS Config, then this will help you write tests that can simulate your code in production.
The AWS Config capabilities in moto work by examining the state of resources that are created within moto, and then returning that data in the way that AWS Config would return it (sans history). This will work by querying all of the moto backends (regions) for a given resource type.
However, this will only work on resource types that have this enabled.
Current enabled resource types
There are several pieces to this for adding new capabilities to moto:
For both, there are a number of pre-requisites:
Base Components
In the moto/core/models.py file is a class named ConfigQueryModel. This is a base class that keeps track of all the resource type backends.
At a minimum, resource types that have this enabled will have:
2.6. AWS Config Support 15
An example of the above is implemented for S3. You can see that by looking at:
Testing
For each resource type, you will need to test write tests for a few separate areas:
Listing
S3 is currently the model implementation, but it also odd in that S3 is a global resource type with regional resource residency.
But for most resource types the following is true:
Implementing the listing capability will be different for each resource type. At a minimum, you will need to return a List of Dict that look like this:
[ { 'type': 'AWS::The AWS Config data type', 'name': 'The name of the resource', 'id': 'The ID of the resource', 'region': 'The region of the resource -- if global, then you may want to have the␣ ˓→calling logic pass in the aggregator region in for the resource region -- or just us-east-1 :P' } , ... ]
16 Chapter 2. Additional Resources