如何对Django的URL进行单元测试?

56

除了我的urls.py之外,我在应用程序的所有地方都实现了100%的测试覆盖率。你有什么建议可以帮助我为我的URL编写“有意义”的单元测试吗?

顺便说一下,我正在尝试测试驱动开发,并希望在编写代码之前就有失败的测试。

3个回答

81

一种方法是使用reverse函数反转URL名称并进行验证。

示例:

urlpatterns = [
    url(r'^archive/(\d{4})/$', archive, name="archive"),
    url(r'^archive-summary/(\d{4})/$', archive, name="archive-summary"),
]

现在,在测试中

from django.urls import reverse

url = reverse('archive', args=[1988])
assertEqual(url, '/archive/1988/')

url = reverse('archive-summary', args=[1988])
assertEqual(url, '/archive-summary/1988/')

你可能正在测试视图。

现在,为了测试URL是否连接到正确的视图,你可以使用resolve

from django.urls import resolve

resolver = resolve('/summary/')
assertEqual(resolver.view_name, 'summary')

现在在变量resolverResolverMatch类实例)中,您有以下选项

 'app_name',
 'app_names',
 'args',
 'func',
 'kwargs',
 'namespace',
 'namespaces',
 'url_name',
 'view_name'

2
FYI,我的同事们已经采用这个概念,并在我们的新单元测试工具库中为其创建了一个 "assert"(https://github.com/incuna/incuna-test-utils/blob/master/incuna_test_utils/testcases/urls.py#L8)。 - meshy
3
我正在使用:assertEqual(resolver.func.func_name, 'archive') 来测试路由转换器是否正确地指向了视图。据我所知,resolver.view_name 实际上是 URL 规则的名称,而不是视图名称。 - petrus-jvrensburg
你是否主张在Django测试中通常使用reverse(...)来处理URL(例如,对于视图),还是仅在这种情况下用于特定的单元测试URL?我看到它在视图测试中经常被使用,但感觉这是一种反模式。 - Taylor D. Edmiston
你为什么认为这是反模式 @tedmiston? - karthikr
因为我可以更改URL中的1个字符来破坏我的API,但所有测试仍将通过。我想我们可以使用简单的assert equals对每个路由进行单元测试...我只是以前没有见过这样做。 - Taylor D. Edmiston
你如何使用get_resolver()测试APPEND_SLASH?似乎即使APPEND_SLASH为True并且配置的urls.py条目中有斜杠,解析器仍会抛出404,但您要解决的内容却没有。这是故意的吗? - radtek

4

在 @karthikr 的答案基础上进行补充:

-> 您可以断言负责解析的视图是您预期的那个,使用 resolver.func.cls

例子

from unittest import TestCase
from django.urls import resolve

from foo.api.v1.views import FooView


class TestUrls(TestCase):
    def test_resolution_for_foo(self):
        resolver = resolve('/api/v1/foo')
        self.assertEqual(resolver.func.cls, FooView)


那么 view_name 是什么? - TheRealFakeNews
1
@AlanH 说实话,我不会对这个名称进行断言。 - Manu Artero
1
尽管可能感觉脆弱,但在名称上进行断言是一种记录的方法。值得考虑。https://docs.djangoproject.com/en/3.2/topics/testing/tools/ - thms

0

非常抱歉我是个“小白”,但我通过关键词“django url testing”找到了这个网站。

我在某种程度上同意我的前辈们的看法,但我也确信有更好的方法来测试您的URL。我们不应使用“resolver = resolve('url/path')”的主要原因是路径相对固定而视图名称则更加灵活。

简单来说,这个更好:

class TestUrls(TestCase):

    def test_foo_url_resolves(self):
        url = reverse('bar:foo')
        self.assertEqual(resolve(url).func.view_class, FooBarView)

'bar:foo' - bar 是一个命名空间,foo 是一个视图名称

比这个更好

class TestUrls(TestCase):
    def test_resolution_for_foo(self):
        resolver = resolve('/api/v1/foo')
        self.assertEqual(resolver.func.cls, FooView)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接