Замена запроса на внешний ресурс объектом JSON в тестировании Django - PullRequest
0 голосов
/ 09 февраля 2020

У меня есть API:

import stripe

class StripeWebHook(APIView):
    permission_classes = (AllowAny,)
    authentication_classes = ()

    def post(self, request, *args, **kwargs):
        payload = request.body
        try:
            event = stripe.Event.construct_from(
                json.loads(payload), stripe.api_key
            )
        except ValueError as e:
            return Response(status=400)

Как мне написать тест, используя patch для тестирования запроса к внешнему API (например, stripe.Event.create), не передавая вызов этой функции из моего main function?

Мне удалось проверить ее, переписав функцию следующим образом:

def get_api_result(payload):
  return stripe.Event.construct_from(
            json.loads(payload), stripe.api_key
        )

class StripeWebHook(APIView):
    def post(self):
      payload = request.body
      res = get_api_result(payload)
      # ...

и используя mock:

import mock
@mock.patch('get_api_result')
def test_payment(self, mockEvent) -> None:
    #...
    mockEvent.return_value = obj

Но я не нравится такой подход. Неправильно, что мне нужно добавить еще одну функцию только для того, чтобы ее смоделировать.

Я пробовал это

import stripe

class StripeWebHookTestCase(APITestCase):    
    @mock.patch('donation.views.stripe.Event.construct_from')
    def test_stripe_web_hook(self, mockEvent) -> None:
        # logic
        mockEvent.return_value = object
        resp = self.client.post(reverse('stripe-web-hook'))

Но я получаю ошибку Expecting value: line 1 column 1 (char 0)

Traceback

  File "/usr/local/lib/python3.7/json/__init__.py", line 348, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.7/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.7/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

структура проекта

project/
  project/
    donation/
      tests/
        test_view.py   (StripeWebHookTestCase)
      views.py         (StripeWebHook)
    settings/
    manage.py

1 Ответ

1 голос
/ 09 февраля 2020

Вы можете просто установить патч stripe.Event.create напрямую. Просто убедитесь, что пропатчен там, где он используется :

patch() работает (временно) изменяя объект, который имя указывает на другое. Может быть много имен, указывающих на любой отдельный объект, поэтому для исправления работайте, вы должны убедиться, что вы исправляете имя, используемое тестируемой системой.

Основой принципа c является то, что вы исправляете, где объект посмотрел , что не обязательно совпадает с местом, где оно определено.

Например, что-то вроде этого должно работать:

@mock.patch('appname.views.stripe.Event.create')
def test_payment(self, mock_event_create) -> None:
    #...
    mock_event_create.return_value = obj

Я рекомендую вам прочитать весь раздел, который цитируется в части выше.

...