Search code examples
pythonpytestmoto

What's wrong with my pytest moto context in this test?


As a frequent user of moto, I'm rather confused about the issue I'm facing. I set up a test class with a pytest fixture providing a DynamoDB table which I want to access in my test. Business as usual:

class TestDynamodbClient:

    @pytest.fixture
    def test_table(self):
        with mock_dynamodb():
            table_name = "test_table"

            dynamodb = boto3.resource('dynamodb')

            params = {
                'TableName': table_name,
                'KeySchema': [
                    {'AttributeName': 'id', 'KeyType': 'HASH'},
                ],
                'AttributeDefinitions': [
                    {'AttributeName': 'id', 'AttributeType': 'N'},
                ],
                'ProvisionedThroughput': {
                    'ReadCapacityUnits': 5,
                    'WriteCapacityUnits': 5
                }
            }

            table = dynamodb.create_table(**params)
            table.wait_until_exists()

            assert table_name in [t.name for t in dynamodb.tables.all()]  # this is to illustrate the setup works

            return table_name

Using the debugger, I confirmed the fixture to be evaluated prior to the test execution. In my test, however, the table does not exist:

    @pytest.mark.integration
    def test_recreate_table__table_exists__recreates_table(self, test_table):
        with mock_dynamodb():
            # given
            client = DynamodbClient()
    
            # this is to illustrate the setup does not work
            dynamodb = boto3.resource('dynamodb')
            assert test_table in [t.name for t in dynamodb.tables.all()]  # raises AssertionError: assert 'test_table' in []

            # when
            client.recreate_table("test_table")

            # then
            # ...

My conftest.py looks as follows:

def pytest_configure(config):
    """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"
    os.environ["AWS_DEFAULT_REGION"] = "eu-central-1"
    os.environ["AWS_REGION"] = "eu-central-1"

    config.addinivalue_line(
        "markers",
        "integration: mark test to run only run as part of the integration test suite",
    )

I'm flabbergasted as to why the "test_table" table does not exist in my test, despite my fixture being evaluated. Does anyone have any pointers towards possible causes?


Solution

  • The issue was caused by the second invocation of with mock_dynamodb() in the test:

    @pytest.mark.integration
    def test_recreate_table__table_exists__recreates_table(self, test_table):
        with mock_dynamodb():  # this seems to create a new moto 'context'
            # given
            client = DynamodbClient()
    

    Upon removing the invocation, everything worked as intended.