如何使用模拟测试服务的响应?

How to test response of service using mock?

我通过 post 请求获得以下服务:

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()

我想模拟请求,以便创建所需的服务响应。 我编写了如下测试:

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()

但是由于 get_req 方法没有 return 响应,断言失败:AttributeError: 'NoneType' object has no attribute 'json'。如何修改断言以检查 get_req 方法的响应是否已相应地模拟到 fake_json 变量?

这是因为您没有 return 从 Attt.get_req 获取任何东西,因此它 return 是 None。所以在你的测试中,就像调用None.json()一样。您应该 return 请求的响应:

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

此外,如文档所述,您应该将代码包装在 attt.py 中,这样它就不会在导入时执行:

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

这看起来不错,因为这只是教程。但请注意,您已经可以使用模拟 requests 模块的库,例如 requests-mock.


更新

如果该方法不会 return 任何东西,那么我们所能做的就是通过向目标功能添加间谍来检查。但请注意,这在现实中没有意义,因为我们正在监视的是 mocked/patched 功能,即 requests.post。这只会有利于学习目的,但实际上,最好不要添加测试,因为它根本不会增加任何价值。为此,我们可以使用 pytest-mock

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