Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

unittest in python not working as expected

We are deploying the code in CI/CD fashion via Terraform. So, we have a lambda function under which I have written a code for retrieving the specific secret creds.

Below is my lambda code:

logger = get_provisioner_logger()
session = boto3.session.Session()
client = session.client(
    service_name="secretsmanager",
    region_name=""
)


def lambda_handler(event, context):
    logger.info("lambda invoked with event: " + str(event))
    domain_name = "db-creds"
    secret_data = getCredentials(domain_name)
    acc = secret_data["acc"]
    user = secret_data["user"]
    password = secret_data["pass"]
    #....
    #here we are invoking other methods where we are passing the above creds
    #....
    return handler.handle(event)


def getCredentials(domain_name):
    try:
        response = client.get_secret_value(SecretId=domain_name)
        result = json.loads(response['SecretString'])
        print(result)
        logger.info("Got value for secret %s.", domain_name)
        return result
    except UnableToRetrieveDetails as e:
        logger.error("unable to retrieve secret details due to ", str(e))
        raise e

Now, I have written a test case where I am trying to mock the client and trying to fake the return value of the response but am unable to do so. Below is my code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

from unittest import TestCase
from unittest.mock import patch
from api.lambda_handler import getCredentials
import json

@patch('api.lambda_handler.client')
class TestSecretManagerMethod(TestCase):

    def test_get_secret_creds(self, sm):
        sm.response.return_value = {"secret":"gotsomecreds"}
        actual = getCredentials("db-creds")
        self.assertEqual(actual, "hey")

It gives me below error:

 raise TypeError(f'the JSON object must be str, bytes or bytearray, '
TypeError: the JSON object must be str, bytes or bytearray, not MagicMock. 

What exactly am I missing here?

>Solution :

Kevin’s answer is on the right track.

The problem is that you’re mixing up what needs to be patched and returned.

In your code you’re saying: If you call client.response() then return {"secret":"gotsomecreds"}. The problem is that this is not what’s happening in your code.

You’re actually calling client.get_secret_value(something) and that’s what needs to be patched:

@patch('api.lambda_handler.client')
class TestSecretManagerMethod(unittest.TestCase):
    def test_get_secret_creds(self, sm):
        sm.get_secret_value.return_value = {
            "SecretString": '{"secret": "gotsomecreds"}',
        }
        actual = getCredentials("db-creds")
        self.assertEqual(actual, {"secret": "gotsomecreds"})

I also took the liberty of fixing the assertion, because the way you set it up "hey" won’t be returned.

As an aside, I highly recommend you check out the moto project. It provides mocks around most of the AWS API and will save you a lot of work.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading