2016-07-26 51 views
1

我在urls.py文件一堆网址是有login_required装饰Django的测试,模拟的有效网址请求

# Index Page 
url(r'^$', login_required(views.IndexPage.as_view()), name='index'), 

# Schedule urls 
url(r'^schedules/$', login_required(views.ScheduleListView.as_view()), 
    name='schedule-list'), 
url(r'^schedule/(?P<pk>[\d]+)/$', 
    login_required(views.ScheduleDetailView.as_view()), 
    name='schedule-detail'), 
url(r'^schedule-freeze/(?P<pk>[\d]+)/$', 
    login_required(views.freezeSchedule), 
    name='schedule-freeze'), 
url(r'^schedule-create/$', login_required(views.ScheduleCreate.as_view()), 
    name='schedule-create'), 
url(r'^schedule-delete/(?P<pk>[\d]+)$', 
    login_required(views.ScheduleDelete.as_view()), 
    name='schedule-delete'), 
url(r'^schedule-update/(?P<pk>[\d]+)/$', 
    login_required(views.ScheduleUpdate.as_view()), 
    name='schedule-update'), 
url(r'^schedule-generate/(?P<pk>[\d]+)/$', 
    login_required(views.scheduleGenerate), name='schedule-generate'), 

# Client urls 
url(r'^clients/$', login_required(views.ClientList.as_view()), 
    name='client-list'), 
url(r'^client/(?P<slug>[\w-]+)/$', 
    login_required(views.ClientDetail.as_view()), name='client-detail'), 
url(r'^client-create/$', login_required(views.ClientCreate.as_view()), 
    name='client-create'), 
url(r'^client-delete/(?P<slug>[\w-]+)/$', 
    login_required(views.ClientDelete.as_view()), name='client-delete'), 
url(r'^client-update/(?P<slug>[\w-]+)/$', 
    login_required(views.ClientUpdate.as_view()), name='client-update'), 

# And so on .... 

对于每一个管窥我试图写一个测试确保未经授权的用户在尝试访问视图时被重定向到登录页面。如果可能的话,我希望能够在单个代码块中实现这一点,而不是为每个URL编写单个测试。

我已经试过类似如下:

list_urls = [e for e in get_resolver(urls).reverse_dict.keys() if isinstance(e, str)] 

for url in list_urls: 
    # Fetches the urlpath e.g. 'client-list' 
    namedspaced_url = 'reports:' + url 
    path = reverse(namedspaced_url) 
    response = self.client.get(path) 
    self.assertEqual(response.status_code, 302) 
    self.assertRedirects(response, reverse('login') + '?next=' + path) 

list_urls返回我的urls.py文件中所有命名的网址即['schedule-create', 'server-detail', 'schedule-list', 'schedule-update', 'index', ....]

名单的问题

这一段代码:reverse(namedspaced_url)

where thi s导致的问题是,每个网址有不同的正则表达式模式,即一些采取slu some一些采取pk的

所以行path = reverse(namedspaced_url)将适用于简单的URL,如那些指向ListViews但将失败的更复杂的URL,如那些指向DetailViews需要蛞蝓的/ PK的,即path = reverse(namedspaces_url, args=[1945])

是否有可能暂时拒绝/忽略Django的模式匹配/路由强制要求去通过(无论通过参数的个数)

还是我必须使用有效的kwargs/args手动为每个URL编写一个测试来满足regex?

是否有另一种完全不同的方法可以为我的所有login_required()视图编写测试?

更新 使用自省,我想出了以下的怪物,以解决我的问题

def test_page_redirects_for_unauthorised_users(self): 
    url_dict = get_resolver(urls).reverse_dict 
    url_list = [e for e in get_resolver(urls).reverse_dict.keys() if 
       isinstance(e, str)] 
    for url in url_list: 
     patterns = url_dict[url][0][0][1] 
     matches = [1 if e == 'pk' else "slug" if e == 'slug' else None for 
        e in patterns] 
     path = reverse('reports:' + url, args=matches) 
     response = self.client.get(path) 
     self.assertEqual(response.status_code, 302) 
     self.assertRedirects(response, reverse('login') + '?next=' + path) 
+1

您应该能够内省url解析器中的项目以获取命名参数。然后,您可以以合适的值调用反向,例如, '1945'代表'pk',或'my-slug'代表'slug'。 – Alasdair

+1

你又来了!我玩弄了这个想法,并被劝告反对它,因为这意味着我不得不拿出样本值来匹配我的网址中的每个正则表达式模式(这很快就会变得混乱)。我想知道是否有一个更清洁的解决方案,因为我肯定有人必须在这个问题之前解决一些问题。但是,谢谢你的建议!(如果这是解决此问题的唯一已知方法,那么我想我只需要这样做) –

回答

2

你正在尝试测试一些非常复杂的东西,因为你已经决定使用login_requireddecorate the urlconf

为什么不用decorate the class代替?这样,你可以简单地测试每个类,以确保它具有装饰器login_required。这消除了嘲笑slug和pk正则表达式值的需要。

+0

我不是很完美接下来,所以你是说,通过将逻辑移到不同的地方,我不再需要担心测试? (基本假设是我可以信任Django的login_required装饰器做正确的事情,即重定向用户)。这与使用login_required在urls.py中包装url有什么不同? –

+1

@JackEvans你可以装饰网址或视图 - 最终的结果是相同的,未经认证的用户将被重定向。在你的情况下,装饰视图更容易测试,因为你可以测试视图是否有装饰器,而不必像你尝试过的那样在你的测试中模拟url'pk'或'slug'值。 – YPCrumble

1

在proect_name/PROJECT_NAME/urls.py urlpatterns = [ url(r'', login_required(include('app_name.urls')), ]

这将适用login_required所有URL在project_name/app_name/urls.py中

+0

这有助于整个应用程序受限的情况。但我给出的限制之一是,将来可能会添加新的路线,不需要登录。这也有相同的问题,当涉及到测试每个单独的视图重定向到登录视图 –

+1

把'@login_required(login_url =“login_url /”)'在你想在视图中限制的每个视图之前'.py – willymwai