我试图使用python模拟包来模拟python请求模块。让我在下面的场景中工作的基本调用是什么?

在views.py中,我有一个函数,它每次都以不同的响应进行各种request .get()调用

def myview(request):
  res1 = requests.get('aurl')
  res2 = request.get('burl')
  res3 = request.get('curl')

在我的测试类中,我想做类似的事情,但不能确定确切的方法调用

步骤1:

# Mock the requests module
# when mockedRequests.get('aurl') is called then return 'a response'
# when mockedRequests.get('burl') is called then return 'b response'
# when mockedRequests.get('curl') is called then return 'c response'

步骤2:

调用我的视图

步骤3:

验证响应包含'a response', 'b response', 'c response'

我如何完成第1步(模拟请求模块)?


当前回答

我将添加这些信息,因为我很难弄清楚如何模拟异步api调用。

以下是我模拟异步调用所做的工作。

这是我想测试的函数

async def get_user_info(headers, payload):
    return await httpx.AsyncClient().post(URI, json=payload, headers=headers)

您仍然需要MockResponse类

class MockResponse:
    def __init__(self, json_data, status_code):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

添加MockResponseAsync类

class MockResponseAsync:
    def __init__(self, json_data, status_code):
        self.response = MockResponse(json_data, status_code)

    async def getResponse(self):
        return self.response

下面是测试。这里重要的是,我之前创建了响应,因为init函数不能是异步的,对getResponse的调用是异步的,所以它都签出了。

@pytest.mark.asyncio
@patch('httpx.AsyncClient')
async def test_get_user_info_valid(self, mock_post):
    """test_get_user_info_valid"""
    # Given
    token_bd = "abc"
    username = "bob"
    payload = {
        'USERNAME': username,
        'DBNAME': 'TEST'
    }
    headers = {
        'Authorization': 'Bearer ' + token_bd,
        'Content-Type': 'application/json'
    }
    async_response = MockResponseAsync("", 200)
    mock_post.return_value.post.return_value = async_response.getResponse()

    # When
    await api_bd.get_user_info(headers, payload)

    # Then
    mock_post.return_value.post.assert_called_once_with(
        URI, json=payload, headers=headers)

如果你有更好的方法告诉我,不过我觉得这样很干净。

其他回答

如果你想模拟一个假响应,另一种方法是简单地实例化一个基本HttpResponse类的实例,如下所示:

from django.http.response import HttpResponseBase

self.fake_response = HttpResponseBase()

只是一个有用的提示给那些仍然挣扎,从urllib或urllib2/urllib3转换到请求,并试图模拟一个响应-我在实现我的模拟时得到了一个稍微令人困惑的错误:

与请求。get(path, auth=HTTPBasicAuth('user', 'pass'), verify=False) as url:

AttributeError: __enter__

当然,如果我知道with如何工作(我不知道),我就会知道这是一个残留的、不必要的上下文(来自PEP 343)。在使用请求库时没有必要,因为它在底层为您做了基本相同的事情。只需删除with并使用bare requests.get(…),就万事大吉了。

对于那些不想为pytest安装额外库的人,这里有一个例子。我将在这里复制一些扩展,基于上面的例子:

import datetime

import requests


class MockResponse:
    def __init__(self, json_data, status_code):
        self.json_data = json_data
        self.status_code = status_code
        self.elapsed = datetime.timedelta(seconds=1)

    # mock json() method always returns a specific testing dictionary
    def json(self):
        return self.json_data


def test_get_json(monkeypatch):
    # Any arguments may be passed and mock_get() will always return our
    # mocked object, which only has the .json() method.
    def mock_get(*args, **kwargs):
        return MockResponse({'mock_key': 'mock_value'}, 418)

    # apply the monkeypatch for requests.get to mock_get
    monkeypatch.setattr(requests, 'get', mock_get)

    # app.get_json, which contains requests.get, uses the monkeypatch
    response = requests.get('https://fakeurl')
    response_json = response.json()

    assert response_json['mock_key'] == 'mock_value'
    assert response.status_code == 418
    assert response.elapsed.total_seconds() == 1


============================= test session starts ==============================
collecting ... collected 1 item

test_so.py::test_get_json PASSED                                          [100%]

============================== 1 passed in 0.07s ===============================

使用requests_mock可以很容易地修补任何请求

pip install requests-mock
from unittest import TestCase
import requests_mock
from <yourmodule> import <method> (auth)

class TestApi(TestCase):
  @requests_mock.Mocker()
  def test_01_authentication(self, m):
        """Successful authentication using username password"""
        token = 'token'
        m.post(f'http://localhost/auth', json= {'token': token})
        act_token =auth("user", "pass")
        self.assertEqual(act_token, token)

对于pytest用户,有一个来自https://pypi.org/project/pytest-responsemock/的方便的fixture

例如,模拟GET到http://some.domain,你可以:

def test_me(response_mock):

    with response_mock('GET http://some.domain -> 200 :Nice'):
        response = send_request()
        assert result.ok
        assert result.content == b'Nice'