【问题标题】:Mock external API POST call in view from test view Python从测试视图 Python 在视图中模拟外部 API POST 调用
【发布时间】:2021-10-30 02:22:53
【问题描述】:

我有一个外部 API POST 调用,它是从我的 views.py 内部进行的:

class MyView(APIView):
  def post(self, request):
    my_headers = {
      "Content-Type": "application/json"
    }
    response = requests.post("https://some-external-api.com", data=json.dumps(request.data), headers=my_headers)

    return Response(status.response.status_code)

如您所见,这是一个非常简单的案例,即使用与视图端点接收到的相同数据对外部 API 进行 POST 调用。

现在,我正在尝试为此创建一个单元测试,同时模拟来自“https://some-external-api.com”的响应,因此我显然不必每次都对其进行实际调用此单元测试运行的时间。但是我遇到了困难,因为我无法让模拟方面工作,并且每次将请求发送到实际的外部端点。

我知道网上有很多示例,但我尝试过的所有示例似乎都不起作用。我还没有看到模拟响应应该来自视图文件本身的示例。截至目前,我有这个:

@patch('requests.post')
def test_external_api_call(self, mock_post)
  mock_post.return_value.ok = True
  response = self.client.post(reverse('my-view'), {
    //my random dummy json object goes here
  }, format='json')

  self.assertEqual(response.status_code, 200)

正如我所提到的,使用上面的代码,实际调用了“https://some-external-api.com”而不是被模拟。

【问题讨论】:

    标签: python unit-testing python-requests python-unittest python-unittest.mock


    【解决方案1】:

    无需重新发明轮子,只需使用请求库的可用模拟程序,例如requests_mock

    import json
    
    import pytest
    import requests
    import requests_mock  # python3 -m pip install requests-mock
    
    
    def post():
        my_headers = {"Content-Type": "application/json"}
        my_data = {"some_key": "some_value"}
    
        response = requests.post("https://some-external-api.com", data=json.dumps(my_data), headers=my_headers)
    
        print(response.status_code, response.json())
    
    
    @pytest.fixture
    def mock_post():
        with requests_mock.Mocker() as requests_mocker:
            def match_data(request):
                """
                This is just optional. Remove if not needed. This will check if the request contains the expected body.
                """
                return request.json() == {"some_key": "some_value"}
    
            requests_mocker.post(
                "https://some-external-api.com",  # Match the target URL.
                additional_matcher=match_data,  # Optional. If you want to match the request body too.
                status_code=200,  # The status code of the response.
                json={"the_result": "was successful!"},  # Optional. The value when .json() is called on the response.
            )
    
            yield
    
    
    def test_requests(mock_post):
        post()
    
    $ pytest -q -rP
    ================================================================================================= PASSES ==================================================================================================
    ______________________________________________________________________________________________ test_requests ______________________________________________________________________________________________
    ------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
    200 {'the_result': 'was successful!'}
    1 passed in 0.04s
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-02
      • 2015-11-11
      • 1970-01-01
      • 1970-01-01
      • 2014-11-20
      • 2019-05-19
      • 2016-09-27
      • 1970-01-01
      相关资源
      最近更新 更多