可以在Django测试中避免使用permission_required装饰器吗?

1 投票
3 回答
2278 浏览
提问于 2025-04-16 21:58

我正在测试一组Django应用程序,这些应用程序大量使用了'permission_required'这个装饰器。这个装饰器会导致我大多数视图返回一个302的HTTP响应。

我想问的是:有没有办法在测试时避免或关闭'permission_required',这样我调用我的视图时就能得到200的响应,而不是302?

谢谢!

3 个回答

0

好的。我找到的解决办法是在TestCase类的setUp方法里创建一个超级用户。我是这样做的:

def setUp(self):
    self.client = Client()
    self.user = User.objects.create_superuser(
        'testuser',
        'test@example.com',
        'easy_password',
    )

然后,当我想测试一个网址时,我这样做:

def test_search_customers(self):
    url = reverse('customer_search')
    response = self.client.get(url)
    # Not logged user. Must return a 302 HTTP code.
    self.assertEquals(response.status_code, 302)
    self.assertEquals(response['Location'], 'http://testserver/unauthorized/?next=/search/customers/')
    # HERE I LOG IN MY SUPERUSER
    self.client.login(username='testuser', password='easy_password')
    response = self.client.get(url, follow=True)
    # Same URL requested with a logged user with permissions. Must return 200 HTTP code.
    self.assertEquals(response.status_code, 200)

这对我来说有效 :)

谢谢大家。祝好,

何塞

1

你可以用一种叫“猴子补丁”的方法来解决这个问题:

import django.contrib.auth.decorators

real_permission_required = decorators.permission_required
# return a function that returns the exact function that was decorated, ignoring arguments
decorators.permission_required = lambda *args, **kwargs: lambda func: func

你需要确保这个操作在使用之前完成,也就是在它所装饰的对象被定义的时候。(比如,当这个模块被引入的时候。)

而且,这个操作必须在它被绑定到其他作用域之前完成。比如在 import django.contrib.auth.decorators 之后是可以的,但必须在 from django.contrib.auth.decorators import permission_required 之前完成。

5

在你的测试用例的设置方法中,直接用超级用户登录就可以了。


from django.test import TestCase
from django.contrib.auth.models import User

class TestThatNeedsLogin(TestCase):
    def setUp(self):
        User.objects.create_superuser(
            'user1',
            'user1@example.com',
            'pswd',
        )
        self.client.login(username="user1", password="pswd")

    def tearDown(self):
        self.client.logout()

    def test_something(self):
        response = self.client.get("/")
        self.assertEqual(200, response.status_code)

撰写回答