使用 unittest.mock 时应该导入还是模拟 Response

Should Response be imported or mocked when using unittest.mock

我正在学习 unittestunittest.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)

这达到了预期的结果,我只是传入了一个对象数组(或字典列表)。

但是,我不确定这是处理此问题的正确方法,以及是否应该使用 Mock()。老实说,我一直无法弄清楚如何正确使用 Mock()MagicMock(),或者找不到解释清楚的教程,所以我尝试使用它:

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

刚刚导致:

TypeError: 'module' object is not callable

关于如何实施这个测试有什么建议吗?

原因

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

此错误来自 isinstance 断言 here

解决方案

如果你想用MockMagicMock模拟Response并通过isinstance检查,你可以使用specspec_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'}])
        ...

备注

创建 MockMagic 时,您应该将要模拟的内容的 属性 名称作为关键字参数传递。在这种情况下,你想模拟 Response.data,因此你应该设置 Mock(data=<DATA_VALUE>)。否则,该值将传递给 Mock 个位置参数。

官方 python 文档还提供了如何使用 mock 模块的清晰示例 here