Search code examples
pythondjangotestingsendgrid

How to mock reponse of instantiated mocked object with python pytest


I'm trying to mock a function that calls the sendgrid API. I want to mock the API library but can't work out where I'm going wrong.

Function which calls the API:

def mailing_list_signup(data: dict):

    email_address = data["email"]
    name = data["contact_name"]

    API_KEY = settings.SENDGRID_API_KEY
    sg = SendGridAPIClient(API_KEY)

    # https://docs.sendgrid.com/api-reference/contacts/add-or-update-a-contact
    data = {
        "contacts": [
            {
                "email": email_address,
                "name": name,
            }
        ]
    }

    response = sg.client.marketing.contacts.put(request_body=data)
    return response

my bad test:

@dataclass
class APIResponse:
    status_code: int = 202
    body: bytes = b"example"


@override_settings(SENDGRID_API_KEY='123')
def test_mailing_list_signup():
    response = APIResponse()
    with mock.patch("myapp.apps.base.business.SendGridAPIClient") as sendgridAPI:
        sendgridAPI.client.marketing.contacts.put.return_value = response

        data = {
                "email": "name@example.com",
                "contact_name": None,
                }
        result = mailing_list_signup(data)

        assert result == response

Pytest tells me the test failed with the following message:

FAILED myapp/apps/base/tests/test_business.py::test_mailing_list_signup - AssertionError: assert <MagicMock name='SendGridAPIClient().client.marketing.contacts.put()' id='4622453344'> == APIClient(status_code=202, body=b'example')


Solution

  • Because a return value of a callable is being mocked, the return value should be set on a callable and not an attribute.

    change sendgridAPI.client.marketing.contacts.put.return_value = response to sendgridAPI.client.marketing.contacts.put().return_value = response