mock secret manager using pytest - python-3.x

I am trying to mock secret manager. Here is the code which is written for secret manager using boto3 which I am trying to mock and test.
utils.py
import boto3
secret_id = os.environ.get("SECRETS")
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId=secret_id)
secrets = json.loads(response['SecretString'])
S3_BUCKET_NAME = secrets["S3_BUCKET_NAME"]
SQS_QUEUE_NAME = secrets["SQS_Queue_Name"]
these variables are then used in different methods.
conftest.py
#pytest.fixture(scope='session', autouse=True)
def secret_manager_resource(aws_credentials):
"""Secret Manager mock client"""
with mock_secretsmanager():
conn = boto3.client("secretsmanager", region_name="us-east-1")
logger.info(f"Secret manager connection {conn}")
yield conn
test_file.py
#contextmanager
def secret_manager_setup(secret_manager_resource):
secret_manager_resource.create_secret(Name="test", SecretString="""{"S3_BUCKET_NAME": "test","SQS_Queue_Name": "test_queue"}""")
yield
class TestSecretManager:
def test_secret_manager(self, secret_manager_resource):
with secret_manager_setup(secret_manager_resource):
try:
result = secret_manager_resource.get_secret_value(SecretId="test")
json_result = json.loads(result['SecretString'])
assert json_result["S3_BUCKET_NAME"] == "test"
assert json_result["SQS_Queue_Name"] == "test_queue"
except Exception as err:
print("Error ---", err)
class TestClass:
def test_some_class(test_var):
from functions.something.some import something
something = someClass({}, param)
When I run pytest it directly goes inside TestClass and calls secret Manager and throws error as it is trying to connect to actual secret manager. Could someone suggest me what can be done to over come this issue?

TestClass is not mocked - so I wouldn't expect that to work. You could use Moto as a class-decorator to ensure everything inside someClass is mocked.
Note that the class-decorator creates a mock around test-methods only, so the code-under-test would have to be inside a test-method for this to work.
#mock_secretsmanager()
class TestClass:
def test_something():
from functions.something.some import something
something = someClass({}, param)
See http://docs.getmoto.org/en/latest/docs/getting_started.html#class-decorator for the documentation and more examples around this.

Related

Python Moto Mock Ec2 Filter

Hi I have a following class/ function
class A:
def __init__(aws_profile_name, aws_region, ec2_id):
self.session = boto3.session.Session(profile_name=aws_profile_name, aws_region)
self.ec2 = EC2(self.session, aws_region, id=ec2_id)
class EC2:
def __init__(self, session, aws_region, id):
self.session = session
self.region = aws_region
self.id = id
self.ec2_resouce = self.session.resource("ec2", region_name=self.region)
self.ec2_client = self.session.client("ec2", region_name=self.region)
self.instance = self.filter_ec2_by_id()
def filter_ec2_by_id(self):
return self.filter(
InstanceIds=[
self.get_instance_id(),
]
)
def filter(self, kwargs):
instances = self.ec2_resouce.instances.filter(**kwargs)
instance_list = [instance for instance in instances]
return instance_list
And here is my test test.py
from unittest import mock
import sys
from moto import mock_ec2
import boto3
#mock_ec2
def test_mock_session():
mock_session_obj = mock.Mock()
ec2 = boto3.resource("ec2", region_name="us-east-1")
reservation = client.run_instances(ImageId="ami-1234", MinCount=2, MaxCount=2)
instance1 = ec2.Instance(reservation["Instances"][0]["InstanceId"])
ec2 = EC2(mock_session_obj, region="us-east-1", id=instance1)
test_mock_session()
With above test code, the test failed with following error
instance_list = [instance for instance in instances]
TypeError: 'Mock' object is not iterable
I think that is because ec2 filter return a collection, but I am not sure how should i mock the result. Any recommendation is welcomed.
TIA
Moto will already mock boto3 for you, and intercept any calls to AWS, so there is no need to use mock_session_obj.
Just use EC2(boto3.session.Session(), region="us-east-1", id=instance1). When calling the filter-function, Moto will intercept it and return any created instances in the correct format.

Python Mock Instantiation of Object

Could someone please let me know how to mock the DatabaseAPI object for below unit test case example. Getting error at getURL in test_load.py file.
File load.py
from database_api import DatabaseAPI
Database_api_client = DatabaseAPI(username, password)
def loadFile():
#some code to load the file
File database_api.py
class DatabaseAPI:
def __init__(self, username, password):
self.getUrl()
def getUrl(self):
requests.options(url=SomeURL, headers=request_header)
File test_load.py
import unittest
from load import loadFile
class TestLoad(unittest.TestCase):
def test_loadFile(self):
#some code to test loadfile
But getting get_url connection error. I need to mock the "Database_api_client = DatabaseAPI(username, password)" object
But getting get_url connection error. I need to mock the "Database_api_client = DatabaseAPI(username, password)" object

Using pytest fixtures in class

I have begun writing unit tests for my Flask API. I have gotten them to work when declared outside of a class. However, for simplicity and OOP constraints, I am trying to have everything run from a class. The issue is I cannot seem to pass any fixture methods to my test class. The code I have here is as follow:
#conftest.py
import os, json, pytest
from ..app import create_app
from flask import Flask
#pytest.fixture
def env_setup():
env_name = os.getenv('FLASK_ENV')
app = create_app(env_name)
return app
I am trying to import env_setup into the following file.
# test_BaseURL.py
import pytest
#pytest.mark.usefixtures("env_setup")
class TestStaticPages:
def setUp(self, env_setup):
"""
Setup Test
"""
self.client = env_setup.test_client()
def test_base_route(self, env_setup):
#client = env_setup.test_client()
url = '/'
html1 = b'Welcome to the API. Please visit '
html2 = b'https://example.com to learn more about this app.'
response = self.client.get(url)
assert response.get_data() == html1 + html2
assert response.status_code == 200
I keep geeting the following error when I run this test:
> response = self.client.get(url)
E AttributeError: 'TestStaticPages' object has no attribute 'client'
src/tests/test_BaseURL.py:18: AttributeError
However if I should uncomment the line with client = env_setup.test_client() it works. For whatever reason it cannot seem to grab the setup from the setUP method and keeps erroring out.
Here is how I fixed my issue:
#conftest.py
import os, json, pytest
from ..app import create_app
from flask import Flask
#pytest.fixture
def client():
env_name = os.getenv('FLASK_ENV')
app = create_app(env_name)
client = app.test_client()
return client
I was then able to import the client into my other test class like so.
#test_StaticView.py
import pytest
#pytest.mark.usefixtures("client")
class TestStaticPages:
def test_base_route(self, client):
url = '/'
html1 = b'Welcome to the API. Please visit '
html2 = b'https://example.com to learn more about this app.'
response = client.get(url)
assert response.get_data() == html1 + html2
assert response.status_code == 200

How to Mock a flask-restful class with kwargs

From Intermediate-Usage Flask-RESTful 0.3.7 documentation
in the Passing Constructor Parameters Into Resources section at the bottom, how would you write a test in order to mock kwargs? Side note: I tweaked it so the Smart Engine class is passed directly rather than being instantiated to a variable then passed.
from flask_restful import Resource
class TodoNext(Resource):
def __init__(self, **kwargs):
# smart_engine is a black box dependency
self.smart_engine = kwargs['smart_engine']
def get(self):
return self.smart_engine.next_todo()
You can inject the required dependency into TodoNext like so:
api.add_resource(TodoNext, '/next',
resource_class_kwargs={ 'smart_engine': SmartEngine() })
Test class in question:
import unittest
class TestTodoNext(unittest.TestCase):
todo_next_instance = TodoNext() # How would you mock smart_engine in this case?
You can use Mock object from unittest.mock to mock smart_engine.
import unittest
from unittest.mock import Mock
class TestTodoNext(unittest.TestCase):
smart_engine = Mock()
smart_engine.next_todo.return_value = "YOUR DESIRED RETURN VALUE"
todo_next_instance = TodoNext(smart_engine=smart_engine)
self.assertEqual(todo_next_instace.get(), "YOUR DESIRED RETURN VALUE")

How can I do http.server do_GET mock unit test?

I am beginner in Unit test. I would like to know how can I do mock unit test of following functions.
import ...
class A(BaseHTTPRequestHandler):
def do_GET(self):
client_ip = self.client_address[0]
if client_id == '10.10.10.10':
self._set_headers_200()
return
else:
self._set_headers_400()
return
Test Class:
import unittest
def test_A_get():
I want to test both 200 and 400 response
Can anybody help me this problem?
I'm working on a similar task. Here is a partial solution I've came up with so far
class TestA(unittest.TestCase):
def setUp(self):
self.mock_request = Mock()
#patch('http.server.HTTPServer')
#patch('my_module.A.do_GET')
def test_do_get(self, mock_do_get, mock_http_server):
"""Test if do_GET method gets called"""
mock_do_get.return_value = "/"
self.mock_request.makefile.return_value = IO(b"GET /")
server = A(self.mock_request, ('127.0.0.1', 8080), mock_http_server)
self.assertTrue(mock_do_get.called)
self.assertEqual(server.do_GET(), "/")

Resources