При использовании unittest.mock ответ должен быть импортирован или высмеян

Я учусь unittest и unittest.mock, причем последнее не совсем понятно.

Я издеваюсь над ответом конечной точки и столкнулся со следующим:

import unittest
from unittest.mock import patch
from rest_framework.test import APIClient

class CoreTestCase(unittest.TestCase):
    
    @patch('core.views.CoreViewSet.list')
    def test_response(self, mock_get):
        mock_get.return_value = [{'hello': 'world'}]
        client = APIClient()
        response = client.get('/core/')
        print(response.data)

Что привело к следующей ошибке:

AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'list'>`

Имеет смысл, потому что DRF использует Response.

Чтобы обойти ошибку, я изменил формулировку на:

import unittest
from unittest.mock import patch
from rest_framework.test import APIClient
from rest_framework.response import Response

class CoreTestCase(unittest.TestCase):
    
    @patch('core.views.CoreViewSet.list')
    def test_response(self, mock_get):
        mock_get.return_value = Response([{'hello': 'world'}])
        client = APIClient()
        response = client.get('/core/')
        print(response.data)

Что достигло желаемого результата, и я просто передавал массив объектов (или список dicts).

Однако я не уверен, что это был правильный способ и что вместо него следовало использовать Mock(). Могу честно сказать, что я не смог понять, как правильно использовать Mock() или MagicMock(), или найти учебник, в котором это четко объясняется, поэтому мои попытки использовать его с:

mock_get.return_value = Mock([{'hello': 'world'}])

В результате:

TypeError: 'module' object is not callable

Есть предложения о том, как следует реализовать этот тест?

Причина

AssertionError: Ожидалось, что из представления будет возвращено Response, HttpResponse или HttpStreamingResponse, но получено <class 'list'>

Эта ошибка происходит из утверждения isinstance здесь.

Решение

Если вы хотите использовать Mock или MagicMock для имитации Response и прохождения isinstance проверки, вы можете использовать spec или spec_set параметр при создании имитации ответа.

class CoreTestCase(unittest.TestCase):
    
    @patch('core.views.CoreViewSet.list')
    def test_response(self, mock_get):
        mock_get.return_value = Mock(spec=Response, data=[{'hello': 'world'}])
        ...

Примечания

При создании Mock или Magic, вы должны передать имя свойства того, что вы хотите высмеять, в качестве аргументов ключевого слова. В данном случае вы хотите поиздеваться над Response.data, поэтому вам следует установить Mock(data=<DATA_VALUE>). В противном случае значение будет передано в позиционные аргументы Mock.

Официальная документация по python также содержит четкие примеры использования mock модуля здесь.

Вернуться на верх