在Django 2中模拟RelatedManager [英] Mocking a RelatedManager in Django 2
问题描述
此问题直接与此问题,但现在看来那已经过时了.
This question is directly related to this question, but that one is now outdated it seems.
我正在尝试测试视图而不必访问数据库.为此,我需要在用户上模拟RelatedManager
.
I am trying to test a view without having to access the database. To do that I need to Mock a RelatedManager
on the user.
我正在使用pytest
和pytest-mock
.
models.py
models.py
# truncated for brevity, taken from django-rest-knox
class AuthToken(models.Model):
user = models.ForeignKey(
User,
null=False,
blank=False,
related_name='auth_token_set',
on_delete=models.CASCADE
)
views.py
class ChangeEmail(APIView):
permission_classes = [permissions.IsAdmin]
serializer_class = serializers.ChangeEmail
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = request.user
user.email = request.validated_data['email']
user.save()
# Logout user from all devices
user.auth_token_set.all().delete() # <--- How do I mock this?
return Response(status=status.HTTP_200_OK)
test_views.py
test_views.py
def test_valid(mocker, user_factory):
user = user_factory.build()
user.id = 1
data = {
'email': 'foo@example.com'
}
factory = APIRequestFactory()
request = factory.post('/', data=data)
force_authenticate(request, user)
mocker.patch.object(user, "save")
related_manager = mocker.patch(
'django.db.models.fields.related.ReverseManyToOneDescriptor.__set__',
return_vaue=mocker.MagicMock()
)
related_manager.all = mocker.MagicMock()
related_manager.all.delete = mocker.MagicMock()
response = ChangeEmail.as_view()(request)
assert response.status_code == status.HTTP_200_OK
从链接的问题的答案中提取了我试图修补的ReverseManyToOneDescriptor
.但是,它似乎并未真正受到嘲笑,因为在尝试删除用户的auth_token_set
时,测试仍在尝试连接数据库.
Drawing from the answer in the linked question I tried to patch the ReverseManyToOneDescriptor
. However, it does not appear to actually get mocked because the test is still trying to connect to the database when it tries to delete the user's auth_token_set
.
推荐答案
您将需要模拟create_reverse_many_to_one_manager
工厂函数的返回值.示例:
You'll need to mock the return value of the create_reverse_many_to_one_manager
factory function. Example:
def test_valid(mocker):
mgr = mocker.MagicMock()
mocker.patch(
'django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager',
return_value=mgr
)
user = user_factory.build()
user.id = 1
...
mgr.assert_called()
请注意,上面的示例将模拟所有模型的转速管理器.如果您需要更细粒度的方法(例如,仅修补程序User.auth_token
的转速管理器,其余未修补),请提供自定义的工厂实现,例如
Beware that the above example will mock the rev manager for all models. If you need a more fine-grained approach (e.g. patch User.auth_token
's rev manager only, leave the rest unpatched), provide a custom factory impl, e.g.
def test_valid(mocker):
mgr = mocker.MagicMock()
factory_orig = related_descriptors.create_reverse_many_to_one_manager
def my_factory(superclass, rel):
if rel.model == User and rel.name == 'auth_token_set':
return mgr
else:
return factory_orig(superclass, rel)
mocker.patch(
'django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager',
my_factory
)
user = user_factory.build()
user.id = 1
...
mgr.assert_called()
这篇关于在Django 2中模拟RelatedManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!