Home > Net >  How to mock multiple dynamodb tables using moto
How to mock multiple dynamodb tables using moto

Time:01-18

I have a function create which uses 3 dynamodb tables. How do i mock three Dynamo db tables?

def create():
    //This function uses a dynamodb table "x"
    // Then it calls my_table() function

def my_table():
    // This function basically uses two dynamodb table "y" and "z"
    // This function returns a value which is used in create() function.

My test file has following code -

@patch.dict(os.environ, {"DYNAMODB_TABLE": "x",
'second_TABLE': "y",
'Third_TABLE': "z"
})
def test_create():

    dynamodb_test()
    event = {  // my event values}

    result = create(event)
    assert result == 200




def dynamodb_test():

    with mock_dynamodb2():
        dynamodb = boto3.client('dynamodb', region_name='us-east-1')
        dynamodb.create_table(
            TableName=os.environ["DYNAMODB_TABLE"],
            KeySchema=[
                {
                'AttributeName': 'id',
                'KeyType': 'HASH'
                }
            ],
            AttributeDefinitions=[
                {
                'AttributeName': 'id',
                'AttributeType': 'S'
                }
            ],
            ProvisionedThroughput={
            'ReadCapacityUnits': 1,
            'WriteCapacityUnits': 1
            }
        )
        yield dynamodb

whenever i am testing test_create() function using pytest , i am getting

botocore.exceptions.ClientError: An error occurred (ExpiredTokenException) when calling the Scan operation: The security token included in the request is expired

I think its trying to access the actual aws dynamo db but i want it to use mock dynamodb. How can i achieve this ?

CodePudding user response:

I believe this post is almost identical to yours. You could try this or utilize some of the other existing tools like localstack or dynamodb-local. The Python client for localstack for example: https://github.com/localstack/localstack-python-client

EDIT: I see your title explains you want to use moto. I don't see you importing moto any of the moto modules into your code. See the last snippet in this page and replace s3 with either dynamodb, dynamodb2 (whichever you are using)

CodePudding user response:

Moto only works when two conditions are met:

  • The logic to be tested is executed inside a Moto-context
  • The Moto-context is started before any boto3-clients (or resources) are created

The Moto-context in your example, with mock_dynamodb2(), is localized to the dynamodb_test-function. After the function finishes, the mock is no longer active, and Boto3 will indeed try to access AWS itself.

Solution

The following test-function would satisfy both criteria:

@patch.dict(os.environ, {"DYNAMODB_TABLE": "x",
'second_TABLE': "y",
'Third_TABLE': "z"
})
# Initialize the mock here, so that it is effective for the entire test duration
@mock_dynamodb2
def test_create():

    dynamodb_test()
    event = {  // my event values}

    # Ensure that any boto3-clients/resources created in the logic are initialized while the mock is active
    from ... import create

    result = create(event)
    assert result == 200

def dynamodb_test():

    # There is no need to start the mock-context again here, so create the table immediately
    dynamodb = boto3.client('dynamodb', region_name='us-east-1')
    dynamodb.create_table(...)


The test code you provided does not talk about creating tables y and z - if the logic expects them to exist, you'd have to create them manually as well of course (just like table x was created in dynamodb_test.


Documentation for the import quirk can be found here: http://docs.getmoto.org/en/latest/docs/getting_started.html#recommended-usage

  •  Tags:  
  • Related