13

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?

Paul Waldo
  • 1,131
  • 10
  • 26

1 Answers1

16

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()
Pete Jeffryes
  • 175
  • 2
  • 9