如何通过mock.patch将ViewSet.filterset_class设为返回None?
问题描述
编写了如下测试代码,意图通过@mock.patch禁用MyViewSet的filterset_class,避免查询参数影响视图行为:
@mock.patch("app.views.MyViewSet.filterset_class", return_value=None) def test_filter_chat_request_management_status(self, mock_filterset_class): query_parameter = "status=accepted" response = self.client.get(URL + "?" + query_parameter) assert 1 == 1
但调试时发现,测试方法作用域内MyViewSet.filterset_class返回的是MagicMock对象而非预期的None:
>>> print(MyViewSet.filterset_class) <MagicMock name='filterset_class' id='4894544640'>
导致DRF的DjangoFilterBackend.get_filterset_class()方法中,getattr(view, "filterset_class", None)拿到的是MagicMock实例,无法达到禁用过滤的效果。
解决方案
问题出在return_value参数的用法上:该参数仅对被mock的方法生效,而你mock的是类属性,patch默认会将目标属性替换为MagicMock实例,return_value在这里不起作用。
有两种方法可以强制让MyViewSet.filterset_class返回None:
方法一:使用new参数直接替换为None
修改patch装饰器,通过new=None直接将目标属性设置为None,无需接收mock参数:
@mock.patch("app.views.MyViewSet.filterset_class", new=None) def test_filter_chat_request_management_status(self): query_parameter = "status=accepted" response = self.client.get(URL + "?" + query_parameter) assert 1 == 1
方法二:在测试方法内手动覆盖mock对象
如果需要保留mock参数(比如后续要做断言),可以在方法内部直接将mock对象赋值为None:
@mock.patch("app.views.MyViewSet.filterset_class") def test_filter_chat_request_management_status(self, mock_filterset_class): mock_filterset_class = None query_parameter = "status=accepted" response = self.client.get(URL + "?" + query_parameter) assert 1 == 1
这两种方法都会让后续访问MyViewSet.filterset_class时得到None,从而让DRF的过滤逻辑跳过该属性,达到禁用过滤的目的。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

