Как смоделировать запрос API, используемый внутри функции в тесте Django?

#python #django #unit-testing #mocking #pytest

#python #django #модульное тестирование #издевательство #pytest

Вопрос:

У меня есть небольшая служебная функция, построенная таким образом, чтобы получать данные из другого API приложений:

 # app/utils.py

import json

import requests
from django.conf import settings

def get_future_assignments(user_id):
    """gets a users future assignments list from the API

    Arguments:
        user_id {int} -- user_id for a User
    """
    headers = {
        "User-Agent": "Mozilla/5.0",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "X-Requested-With": "XMLHttpRequest",
    }
    api_app = settings.ASSIGNMENTS_API_ROOT_URL # http://project.org/appname/
    api_model = "futureassignments/"
    api_query = "?user_id="   str(user_id)
    json_response = requests.get(
        api_app   api_model   api_query, headers=headers, verify=False
    )
    return json.loads(json_response.content)
 

Он в основном создает вызов API и возвращает данные ответа — я бы хотел это протестировать.

 # tests/test_utils.py

import mock
from unittest.mock import patch, Mock
from django.test import TestCase

from app.utils import get_future_assignments

class UtilsTest(TestCase):
    def setUp(self):
        self.futureassignments = [
            {
                "id": 342,
                "user_id": 18888,
                "job": 361,
                "location": "1234",
                "building": "Building One",
                "confirmed_at": None,
                "returning": None,
                "signature": None,
            },
            {
                "id": 342,
                "user_id": 18888,
                "job": 361,
                "location": "1235",
                "building": "Building Two",
                "confirmed_at": None,
                "returning": None,
                "signature": None,
            },
        ]

    @patch("app.utils.get_future_assignments")
    def test_get_future_assignments_with_multi_assignments(self, mock_gfa):
        """
        Test for getting future assignments for a user with mocked API
        """
        mock_gfa.return_value = Mock()
        # set the json response to what we're expecting
        mock_gfa.return_value.json.return_value = self.futureassignments
        assignments = get_future_assignments(18888)
        self.assertEqual(len(assignments), 2)
 

Он продолжает выдавать мне сообщение об ошибке, что он не может получить доступ к API для получения ответа (что ожидается в данный момент — поскольку я запускаю его локально, и он не может попасть в API)

Я новичок в использовании Mock — так что, возможно, я здесь далеко не прав.

Есть идеи?

Комментарии:

1. Поскольку вы хотите имитировать ответ API, вы должны исправить requests.get функцию, а не свою собственную функцию, которую вы хотите протестировать.

2. В настоящее время этот тест немного глуповат (даже если вы издеваетесь над запросами). Поскольку вы тестируете заголовки настроек, которые вы не используете, и встроенную способность json анализировать смоделированный ответ.

3. Итак, Мелвин — как бы вы изменили его? Быть критичным и не давать возможности улучшить ситуацию или изменить ситуацию к лучшему — это… не помогает.

Ответ №1:

Как и вы, я тоже новичок в использовании mock . Я считаю, что это должно работать именно так:

     @patch("requests.get")
    def test_get_future_assignments_with_multi_assignments(self, mock_requests_get):
        """
        Test for getting future assignments for a user with mocked API
        """
        mock_requests_get.return_value = json.dumps(self.futureassignments)
        assignments = get_future_assignments(18888)
        self.assertEqual(len(assignments), 2)
 

Пожалуйста, поправьте меня, если я ошибаюсь!