当详细视图上的force_login() 时,Django Rest Framework 在单元测试中给出 302?

kra*_*r65 5 python authentication django unit-testing django-rest-framework

我正在使用 Django Rest Framework 来提供 API。我进行了一些测试,效果很好。要发表帖子,用户需要登录,我还对登录用户的详细视图进行一些检查。我这样做如下:

class DeviceTestCase(APITestCase):
    USERNAME = "username"
    EMAIL = 'a@b.com'
    PASSWORD = "password"

    def setUp(self):
        self.sa_group, _ = Group.objects.get_or_create(name=settings.KEYCLOAK_SA_WRITE_PERMISSION_NAME)
        self.authorized_user = User.objects.create_user(self.USERNAME, self.EMAIL, self.PASSWORD)
        self.sa_group.user_set.add(self.authorized_user)

    def test_post(self):
        device = DeviceFactory.build()
        url = reverse('device-list')

        self.client.force_login(self.authorized_user)
        response = self.client.post(url, data={'some': 'test', 'data': 'here'}, format='json')
        self.client.logout()

        self.assertEqual(status.HTTP_201_CREATED, response.status_code)
        # And some more tests here

    def test_detail_logged_in(self):
        device = DeviceFactory.create()

        url = reverse('device-detail', kwargs={'pk': device.pk})

        self.client.force_login(self.authorized_user)
        response = self.client.get(url)
        self.client.logout()

        self.assertEqual(status.HTTP_200_OK, response.status_code, 'Wrong response code for {}'.format(url))
        # And some more tests here
Run Code Online (Sandbox Code Playgroud)

第一次测试效果很好。它发布了新记录并且所有检查都通过了。但第二次测试失败了。它给出了一个错误说

AssertionError: 200 != 302 : Wrong response code for /sa/devices/1/
Run Code Online (Sandbox Code Playgroud)

事实证明,列表视图将用户重定向到登录屏幕。为什么第一个测试使用户完美登录,但第二个测试却将用户重定向到登录屏幕?我错过了什么吗?

这是视图:

class APIAuthGroup(InAuthGroup):
    """
A permission to allow all GETS, but only allow a POST if a user is logged in,
and is a member of the slimme apparaten role inside keycloak.
    """
    allowed_group_names = [settings.KEYCLOAK_SA_WRITE_PERMISSION_NAME]

    def has_permission(self, request, view):
        return request.method in SAFE_METHODS \
               or super(APIAuthGroup, self).has_permission(request, view)


class DevicesViewSet(DatapuntViewSetWritable):
    """
    A view that will return the devices and makes it possible to post new ones
    """

    queryset = Device.objects.all().order_by('id')

    serializer_class = DeviceSerializer
    serializer_detail_class = DeviceSerializer

    http_method_names = ['post', 'list', 'get']

    permission_classes = [APIAuthGroup]
Run Code Online (Sandbox Code Playgroud)

Sch*_*nge 1

所以我想你已经测试过这个并且你仍然得到相同的结果:

class APIAuthGroup(InAuthGroup):
    def has_permission(self, request, view):
        return True
Run Code Online (Sandbox Code Playgroud)

DeviceFactory.build()为什么在第一个测试和DeviceFactory.create()第二个测试中使用?

也许两者的合并可以帮助你:

def test_get(self):
    device = DeviceFactory.build()
    url = reverse('device-list')
    response = self.client.get(url)
    self.assertEqual(status.HTTP_200_OK, response.status_code)
Run Code Online (Sandbox Code Playgroud)