Chris
Chris

Reputation: 607

Moto doesn't mock DynamoDB

I'm trying to write my unit tests for a Lambda function that communicates with DynamoDB. I'm using moto but it isn't mocking anything. Whenever I call something in boto3, it communicates using my AWS CLI profile to the actual API and not a mock one. Why is this happening?

Here's the code:

### Unit test for the visitorCounterLambda function

from visitorCounterLambda import handler
import boto3
from moto import mock_dynamodb2


def setUp(self):
  #pass
  self.region = 'us-east-2'

@mock_dynamodb2
def test_handler():
  dynamodb = boto3.client('dynamodb')
  ddbTableName = "myDDBtable"

  # table = dynamodb.create_table(
  #   TableName = ddbTableName,
  #   BillingMode='PAY_PER_REQUEST',
  #   AttributeDefinitions=[
  #       {
  #           'AttributeName': 'id',
  #           'AttributeType': 'S'
  #       },
  #   ],
  #   KeySchema=[
  #       {
  #           'AttributeName': 'id',
  #           'KeyType': 'HASH'
  #       },
  #   ]
  # )
  tablesListed = dynamodb.list_tables()
  print(tablesListed)



if __name__ == '__main__':
    test_handler()

print(tablesListed) returns my actual tables from my actual account. If I uncomment the create_table command, it creates the table in my AWS account as well.

What am I missing here? Thanks

Upvotes: 4

Views: 10778

Answers (2)

Octave
Octave

Reputation: 444

In my humble opinion: stay away from moto. Each and every single version comes with other issues.

  • We have been using it for years and had to solve tricky bugs on every update of boto3, sometimes leaving the whole test suite broken for weeks. It is not possible to live in the fear of an upgrade.
  • When using features that are a bit more advanced, you often end up with a crpytic error messages, that finally lead you to conclude that the feature in question is not supported.

Rewritting the whole test suite to go out of such a dependency is a pain, and of course always come at the wrong time, Murphy's law.

Mock AWS dependencies yourself for unit testing, and rely on integration tests to confirm the whole thinkg is working.

Upvotes: 4

Chris
Chris

Reputation: 607

I found out that the issue was with the from visitorCounterLambda import handler part because that script already established a boto3 client when imported and therefore mock could not break that. The proper way of doing it is outlined in the Moto documentation under "Very Important -- Recommended Usage". You should first establish the @mock_dynamodb2 then after that import your external resources into the function.

Example:

import boto3
from moto import mock_dynamodb2

@mock_dynamodb2
def test_handler():
  from visitorCounterLambda import handler
  dynamodb = boto3.client('dynamodb')

  ## do your magic here

  tablesListed = dynamodb.list_tables()
  print(tablesListed)

Upvotes: 2

Related Questions