I'm working with moto and Python 3.7 to mock some S3 interaction. It appears that moto is working properly if all of the mocking code is contained in the test method. When I move some of the preliminary code to setUp()
, the test fails as if setUp()
has never run.
import unittest
import boto3
from moto import mock_s3
class BucketFacadeTests(unittest.TestCase):
@mock_s3
def setUp(self):
print('setUp called')
s3 = boto3.resource('s3', region_name='us-east-1')
s3.create_bucket(Bucket='bucket')
key = 'a/b/c/d.txt'
object = s3.Object('bucket', key)
object.put(Body='my dog has fleas')
def do_test(self):
s3 = boto3.resource('s3', region_name='us-east-1')
the_object = s3.Object('bucket', 'a/b/c/d.txt')
string_data = the_object.get()['Body'].read().decode('utf-8')
self.assertEqual('my dog has fleas', string_data)
@mock_s3
def test_bucket_can_be_accessed_with_setup(self):
self.do_test()
@mock_s3
def test_bucket_can_be_accessed_without_setup(self):
# This does what setUp() should
s3 = boto3.resource('s3', region_name='us-east-1')
s3.create_bucket(Bucket='bucket')
key = 'a/b/c/d.txt'
object = s3.Object('bucket', key)
object.put(Body='my dog has fleas')
self.do_test()
When I don't rely on setUp()
, everything runs as expected
Testing started at 07:49 ...
/Users/paul/.virtualenvs/nui-converter/bin/python "/Applications/PyCharm CE.app/Contents/helpers/pycharm/_jb_unittest_runner.py" --target BucketFacade2Tests.BucketFacadeTests.test_bucket_can_be_accessed_without_setup
Launching unittests with arguments python -m unittest BucketFacade2Tests.BucketFacadeTests.test_bucket_can_be_accessed_without_setup in /Users/Paul/as/nui-converter/tests/InventoryLoader
setUp called
Ran 1 test in 0.103s
OK
Process finished with exit code 0
Yet it fails when I do rely on setUp()
Testing started at 07:56 ...
/Users/paul/.virtualenvs/nui-converter/bin/python "/Applications/PyCharm CE.app/Contents/helpers/pycharm/_jb_unittest_runner.py" --target BucketFacade2Tests.BucketFacadeTests.test_bucket_can_be_accessed_with_setup
Launching unittests with arguments python -m unittest BucketFacade2Tests.BucketFacadeTests.test_bucket_can_be_accessed_with_setup in /Users/Paul/as/nui-converter/tests/InventoryLoader
setUp called
Ran 1 test in 0.183s
FAILED (errors=1)
Error
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 615, in run
testMethod()
File "/Users/paul/.virtualenvs/nui-converter/lib/python3.7/site-packages/moto/core/models.py", line 74, in wrapper
result = func(*args, **kwargs)
File "/Users/Paul/as/nui-converter/tests/InventoryLoader/BucketFacade2Tests.py", line 27, in test_bucket_can_be_accessed_with_setup
self.do_test()
File "/Users/Paul/as/nui-converter/tests/InventoryLoader/BucketFacade2Tests.py", line 22, in do_test
string_data = the_object.get()['Body'].read().decode('utf-8')
File "/Users/paul/.virtualenvs/nui-converter/lib/python3.7/site-packages/boto3/resources/factory.py", line 520, in do_action
response = action(self, *args, **kwargs)
File "/Users/paul/.virtualenvs/nui-converter/lib/python3.7/site-packages/boto3/resources/action.py", line 83, in __call__
response = getattr(parent.meta.client, operation_name)(**params)
File "/Users/paul/.virtualenvs/nui-converter/lib/python3.7/site-packages/botocore/client.py", line 357, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/Users/paul/.virtualenvs/nui-converter/lib/python3.7/site-packages/botocore/client.py", line 661, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.errorfactory.NoSuchBucket: An error occurred (NoSuchBucket) when calling the GetObject operation: The specified bucket does not exist
Process finished with exit code 1
Am I doing something wrong or pushing moto beyond its limits?
Moto (https://github.com/spulec/moto) is an open source Python library that provides an easy way of abstracting AWS resource for Python's built-in unit test mock library.
The command to run the tests is python -m unittest filename.py . In our case, the command to run the tests is python -m unittest test_utils.py .
The problem is you are applying the mock_s3 decorator to the setUp()
method and test methods
directly. This results in separate mock s3 environments and therefore do not share anything done in the setUp()
method.
The solution is to apply the @mock_s3
decorator to the entire BucketFacadeTests
class.
The below code should work as expected.
import unittest
import boto3
from moto import mock_s3
@mock_s3
class BucketFacadeTests(unittest.TestCase):
def setUp(self):
print('setUp called')
s3 = boto3.resource('s3', region_name='us-east-1')
s3.create_bucket(Bucket='bucket')
key = 'a/b/c/d.txt'
object = s3.Object('bucket', key)
object.put(Body='my dog has fleas')
def do_test(self):
s3 = boto3.resource('s3', region_name='us-east-1')
the_object = s3.Object('bucket', 'a/b/c/d.txt')
string_data = the_object.get()['Body'].read().decode('utf-8')
self.assertEqual('my dog has fleas', string_data)
def test_bucket_can_be_accessed_with_setup(self):
self.do_test()
def test_bucket_can_be_accessed_without_setup(self):
# This does what setUp() should
s3 = boto3.resource('s3', region_name='us-east-1')
s3.create_bucket(Bucket='bucket')
key = 'a/b/c/d.txt'
object = s3.Object('bucket', key)
object.put(Body='my dog has fleas')
self.do_test()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With