码农家园

关闭
导航

关于python:如何测试视图是否用“login_required”装饰(Django)


decoratordjangologin-requiredpythontesting

How to test if a view is decorated with “login_required” (Django)

我正在为一个用"login_required"装饰的视图做一些(隔离的)单元测试。 例:

1
2
3
@login_required
def my_view(request):
    return HttpResponse('test')

是否可以测试"my_view"函数是否用"login_required"修饰?

我知道我可以通过集成测试(使用测试客户端)来测试行为(匿名用户被重定向到登录页面),但我想通过隔离测试来完成。

任何的想法?

谢谢!

相关讨论

  • 在您的测试中,使用AnonymousUser将request设置为与myview相关联的URL,它应返回403 Forbidden Status
  • 试试这篇博文
  • @Gocht,谢谢,但正如我上面所说,我知道我可以测试与Django测试客户端进行集成测试的行为,但在这种情况下,我想用隔离的纯单元测试来做。
  • @Alasdair,有趣,但我找不到解决方案。 我看到当视图没有被装饰时,该函数没有"func_closure",当它执行时,func_closure返回一个包含4个项目的元组。 最后一项实际上是视图函数"my_view",所以我不确定是否应该将其视为"视图由login_required函数修饰",因为我找不到使用func_closure和cell_contents对"login_required"的任何引用


当然,必须有可能以某种方式测试它。不过,这绝对不值得。编写完全隔离的单元测试来检查装饰器是否应用只会导致非常复杂的测试。测试错误的可能性高于测试行为错误的可能性。我强烈反对它。

测试它的最简单方法是使用Django的Client伪造对相关URL的请求,并检查重定向。如果您使用任何Django的测试用例作为基类:

1
2
3
4
class MyTestCase(django.test.TestCase):
    def test_login_required(self):
        response = self.client.get(reverse(my_view))
        self.assertRedirects(response, reverse('login'))

稍微复杂但稍微孤立的测试是使用RequestFactory直接调用视图来创建请求对象。 assertRedirects()在这种情况下不起作用,因为它取决于Client设置的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.test.client import RequestFactory

class MyTestCase(django.test.TestCase):
    @classmethod
    def setUpClass(cls):
        super(MyTestCase, cls).setUpClass()
        self.rf = RequestFactory()

    def test_login_required(self):
        request = self.rf.get('/path/to/view')
        response = my_view(request, *args, **kwargs)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['Location'], login_url)
        ...
相关讨论

  • 谢谢,但正如我上面所说,我知道我可以测试与Django测试客户端进行集成测试的行为,但在这种情况下,我想用隔离的纯单元测试来做。
  • @goathi单元测试是否应用装饰器是复杂的,不值得IMO。我通过功能测试更新了我的答案。我不会使用比这更多的粒度来测试login_required。
  • 好吧,检查装饰器是否定义的一个很好的理由是我不必测试行为(如果他没有经过身份验证,则将用户重定向到登录页面),这已经被Django测试过了。我同意你的观点,认为它不值得。或许我根本不应该使用装饰器?
  • 我会使用装饰器,它易于使用并由Django测试。您只需要测试装饰器是否应用于您的视图,如果未经身份验证的请求进入,则由正确的行为暗示。这就是测试的全部内容。


在用户登录和未登录时,使用Django的测试客户端检查是否有正确的重定向。

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.test import TestCase
from django.core.urlresolvers import reverse

class TestLoginRequired(django.test.TestCase):

    def test_redirects_to_login_page_on_not_loggedin(self):
        response = self.client.get(reverse(my_view))
        self.assertRedirects(response, reverse('login_page'))

    def test_redirects_to_test_page_on_loggedin(self):
        self.client.login(username='my_username', password='my_password')
        response = self.client.get(reverse(my_view))
        self.assertRedirects(response, reverse('test'))

MOCK图书馆:

对于隔离测试或"纯"单元测试,您可以使用mock模块。

Mock是一个用于Python测试的库。它允许您使用模拟对象替换受测试系统的部分,并对如何使用它们进行断言。
Mock基于'action - >断言'模式,而不是许多模拟框架使用的'record - > replay'。

您将不得不创建一个模拟对象。模拟对象在您访问它们时会创建所有属性和方法,并存储它们的使用方式的详细信息。您可以配置它们,指定返回值或限制可用的属性,然后对它们的使用方式进行断言:

使用模拟对象的测试将仅测试my_view函数是否用login_required修饰。您无需设置其他属性。

查看有关如何使用此链接使用模拟对象编写测试的文档。

此外,遵循SO链接可能有助于如何猴子修补装饰器。

  • 我怎样才能在测试时对Django模型中的装饰器进行猴子修补?
  • 我可以在包装函数之前修补Python装饰器吗?
相关讨论

  • 谢谢,但正如我上面所说,我知道我可以测试与Django测试客户端进行集成测试的行为,但在这种情况下,我想用隔离的纯单元测试来做。
  • 查看mock库以编写隔离的纯单元测试。我认为这可能会有所帮助。
  • 谢谢@Rahul,我知道Mock库,我经常使用它,但我无法用它来测试装饰器的定义。
  • 你需要修补装饰器。我没有太多经验。试试这些链接:stackoverflow.com/questions/14023763/… stackoverflow.com/questions/7667567/…
  • 我想你可以测试在login_required装饰器包装器中是否将my_view称为arg。


使用requests库,如果你没有传递一个auth cookie,你可以根据它是否返回401 / 403/200 /无论测试需要登录

1
2
3
4
5
6
import requests
req = requests.get("http://yoururl.com")
if req.status_code ==200:
    print"login not needed apparently"
else:
    print"check for other status codes or redirect"
相关讨论

  • 谢谢,但正如我上面所说,我知道我可以测试与Django测试客户端进行集成测试的行为,但在这种情况下,我想用隔离的纯单元测试来做。


    Copyright ©  码农家园 联系:[email protected]