2016-07-26 28 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