Home > OS >  unittest in python not working as expected
unittest in python not working as expected

Time:12-22

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:

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?

CodePudding user response:

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.

  • Related