Home > Net >  How to test response of service using mock?
How to test response of service using mock?

Time:09-24

I have the following service with a post request:

import requests

class Attt():
    def get_req(self):
        pload = {'username': 'Olivia', 'password': '123'}
        r = requests.post('https://httpbin.org/post', data=pload)
        print(r.text)
        print(r.content)


obj=Attt()
obj.get_req()

I would like to mock the request so that I can create the needed response of the service. I have written a test like below:

import unittest
from unittest.mock import patch
from mock_tutorial.attt import Attt
import pandas as pd

class TestMockService(unittest.TestCase):

    def test_mock(self):

        fake_json = [{'test': "mock"}]

        with patch('mock_tutorial.attt.requests.post') as mock_get:
            mock_get.return_value.status_code = 200
            mock_get.return_value.json.return_value = fake_json

            obj = Attt()
            response = obj.get_req()
            print('response json', response.json())

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json(), fake_json)


if __name__ == "__main__":
    unittest.main()

But as the get_req method doesn't return the reesponse, the assertions fail: AttributeError: 'NoneType' object has no attribute 'json'. How can I modify the assertions to check that the response of the get_req method has been mocked correspondingly, to the fake_json variable?

CodePudding user response:

It is because you are not returning anything from Attt.get_req thus it returns None. So in your test, it is like calling None.json(). You should return the response of the request:

...
class Attt():
    def get_req(self):
        ...
        return r
...

Also as documented, you should wrap your code in attt.py so that it doesn't get executed when imported:

if __name__ == "__main__":
    obj=Attt()
    obj.get_req()

This seems fine since this is just for tutorial. But take note that there are already libraries you can use that mocks the requests module such as requests-mock.


Update

If the method wouldn't return anything, then all we can do to check is by adding a spy to the target functionality. But take note that this wouldn't make sense in reality because what we are spying on is a mocked/patched functionality which is requests.post. This would only be good for learning purposes but in reality, better yet not add the test as it doesn't add any value at all. We can use pytest-mock for this purpose:

mock_tutorial/attt.py

import requests

class Attt():
    def get_req(self):
        pload = {'username': 'Olivia', 'password': '123'}
        r = requests.post('https://httpbin.org/post', data=pload)
        print(r.text)
        print(r.content)

test_attt.py

from unittest.mock import patch
from mock_tutorial import attt
from mock_tutorial.attt import Attt

import pytest


def test_mock(mocker):  # Run <pip install pytest-mock>
    fake_json = [{'test': "mock"}]

    with patch('mock_tutorial.attt.requests.post') as mock_get:
        mock_get.return_value.status_code = 200
        mock_get.return_value.json.return_value = fake_json

        post_spy = mocker.spy(attt.requests, "post")

        obj = Attt()
        response = obj.get_req()

        assert post_spy.spy_return.status_code == 200
        assert post_spy.spy_return.json() == fake_json
  • Related