Introduction Python’s Moto Library — Easily Mock Out AWS Services
Add more validity to your tests
Unit tests are our first line of defense against regressive code changes.
If your Python code involves the usage of AWS resources, you might find this article useful for your testing coverage.
Resource Optimism
Resource optimism is a test smell that occurs when a test case makes an optimistic assumption about an external resource.
Either the test function itself uses an external resource, or the parts of code that it tests uses an external resource — which is not guaranteed to be available at test execution time.
The outcome of resource optimism could be flakiness in test execution, in other words, the test shows a pass
or fail
result when executed against the same code base.
Another problem could be the need to manage these external resources in the test setup, making it unrealistic and cumbersome.
AWS
resources such as S3
buckets or sqs
queues are external resources, and as such, they should be regarded as suspects for optimism.
Therefore, when running our unit tests, we want to make sure they do not depend on available AWS resources. The common practice to achieve that is mocking.
Introducing MOTO
Moto is an open source library that provides an easy abstraction to Python’s built-in unit test mock library.
Its documentation is awesome, and it supports a rich set of AWS functionalities, relieving the need to develop mocks on your own.
This way you can focus on writing your unit test to high coverage.
Hands On
Let's have a look at a simple Python class:
Project
class defines a state of a project.
When initialized, it creates two resources: one is an s3
bucket; the other is the SQS
queue, which also generates a client object to AWS SQS and s3 using the boto3 library.
In addition to that, it has a state, which is expressed as a UUID.
When save
is called, the state changes, and the input message
is stored into an s3 bucket.
When restore
is called, the previously saved message is called from s3, and then a notification is sent to the SQS
queue.
After that, the message is returned to the outer context.
Let's write a simple unit test:
This test is terrible as it relies on the external AWS resources, but thanks to moto, this can be easily improved with only three lines of code (lazy programmers will appreciate that :D).
First, let’s install moto from PyPI:
pip install moto
Now, let's use moto in our test code:
First, we import the s3_mock
andsqs_mock
from moto.
These two are decorators
, and they can decorate either functions or classes, creating a mock out of all AWS resource handling calls in the decorated code block.
Now we can decorate
the class TestMyAws
and in all subsequent code blocks, AWS will be mocked.
In this code, we can also see that we do not need to manage secrets since all calls are mocked.
Let's run the test:
python -m unittest test/test_basic.py
Output:
.
----------------------------------------------------------------------
Ran 1 test in 1.074sOK
A Final Note
In our init test code, we want as much isolation as possible.
However, this does not always apply to more robust tests, integration tests, API tests, regression tests, or E2E.
Sometimes, we do need to use the actual resource or to use mock servers.
Moto allows you to write stable tests and to be more concise in your test code.
Thanks for reading.