Hello
I have been trying to create a pytest fixture for s3 that contains a bucket that is created in the fixture.
@pytest.fixture
@mock_s3
def s3_hook():
result = sut.S3Hook()
result.location = 'test_location'
result.connection = boto3.client('s3')
result.connection.create_bucket(Bucket=result.location)
return result
My test looks like this:
@mock_s3
def test_check_existing_file(s3_hook):
saved_string = "Just writing some tests."
s3_hook.connection.put_object(Bucket=s3_hook.location,
Key='test_file',
Body=saved_string)
assert s3_hook.check_for_file('test_file')
This fails with the message
<Message>The specified bucket does not exist</Message>
If I update the test to create the bucket at the start of the test the test starts passing.
s3_hook.connection.create_bucket(Bucket=s3_hook.location)
Any thoughts on this?
I am using:
pytest==2.8.0
moto==0.4.24
Thanks
When using the decorator the state gets cleared right after s3_hook() gets executed, so in test_* you're getting a brand new state. You could get around that by creating the mock object manually (note that m would have to be accessible by both methods):
m = mock_s3()
m.start()
Then running m.stop() after the test runs; not sure how to do that with pytest fixtures though.
For pytest, I've had success making a fixture like this:
@pytest.yield_fixture(scope="function")
def s3_fixture():
mock_s3().start()
client = boto3.client("s3")
resource = boto3.resource("s3")
yield client, resource
mock_s3().stop()
And then just using the fixture in my tests:
def test_s3_thing(s3_fixture):
client = s3_fixture[0]
client.create_bucket(Bucket="some-test-bucket")
You don't want to mock_s3() again before your test.
I've had success making a fixture like this
Me too. You know, I feel like you just deprecated pytest-moto with that!
Going to close this. Feel free to reopen if this solution doesn't work.
@mikegrima ty for the "you don't want to mock again before test" line. fixed my problem!
Fixing double instantiation of mock_s3() in @mikegrima's above comment (breaks in latest version of moto) referenced here: https://github.com/spulec/moto/issues/2559
@pytest.yield_fixture(scope="function")
def s3_fixture():
mocks3 = mock_s3()
mocks3.start()
client = boto3.client("s3")
resource = boto3.resource("s3")
yield client, resource
mocks3.stop()
Using a context manager:
@pytest.yield_fixture(scope="function")
def s3_fixture():
with mock_s3():
client = boto3.client("s3")
resource = boto3.resource("s3")
yield client, resource
Most helpful comment
For pytest, I've had success making a fixture like this:
And then just using the fixture in my tests:
You don't want to
mock_s3()again before your test.