Django如何测试应用所有URL需登录认证 适配带pk参数路由
Django全URL未认证重定向测试实现
核心问题解决方案
- 完整URL列表获取:不要直接导入单文件的
urlpatterns变量遍历,这种方式会漏掉include()引入的子路由、嵌套路由。直接使用Django内置的URL解析器get_resolver递归遍历全量已注册路由,可自动识别路由所属的应用、命名空间,拿到完整可访问路径。 - 带
pk参数的URL自动传值:完全支持自动填充测试参数,遍历路由时识别路径内的所有占位参数,统一传入pk=1即可适配你预先通过fixture生成的测试资源。
可直接复用的测试代码
from django.test import TestCase from django.urls import reverse, get_resolver, URLPattern, URLResolver from my_app import apps # 替换为你自己的待测试应用 # 配置不需要认证校验的公开URL名称,比如登录页、公开首页等 EXEMPT_URL_NAMES = {"login_app:login"} # 默认测试参数值,适配你预先生成的pk=1的fixture数据 DEFAULT_TEST_KWARGS = {"pk": 1, "id": 1} def get_all_app_urls(app_config, resolver=None, parent_namespace=None): """递归获取指定应用下所有可访问的完整URL路径""" if resolver is None: resolver = get_resolver() url_list = [] for url_pattern in resolver.url_patterns: # 处理嵌套的路由分发(include引入的子路由) if isinstance(url_pattern, URLResolver): current_namespace = f"{parent_namespace}:{url_pattern.namespace}" if parent_namespace and url_pattern.namespace else url_pattern.namespace or parent_namespace url_list.extend( get_all_app_urls(app_config, url_pattern, current_namespace) ) continue # 只处理目标应用下的路由 if not hasattr(url_pattern.callback, "__module__"): continue if app_config.name not in url_pattern.callback.__module__: continue # 拼接完整的路由命名 pattern_name = f"{parent_namespace}:{url_pattern.name}" if parent_namespace and url_pattern.name else url_pattern.name if not pattern_name or pattern_name in EXEMPT_URL_NAMES: continue # 识别路由需要的参数,自动填充默认测试值 try: required_kwargs = set(url_pattern.pattern.converters.keys()) reverse_kwargs = {k: v for k, v in DEFAULT_TEST_KWARGS.items() if k in required_kwargs} # 其余未识别的参数统一传1,适配其他类似主键的路径参数 for kwarg in required_kwargs - set(reverse_kwargs.keys()): reverse_kwargs[kwarg] = 1 full_url = reverse(pattern_name, kwargs=reverse_kwargs) url_list.append(full_url) except Exception: # 遇到特殊参数无法自动生成URL的,可手动加入EXEMPT列表跳过 continue return url_list class AuthRedirectTest(TestCase): # 加载你预先准备好的pk=1的fixture fixtures = ["your_test_fixture.json"] @classmethod def setUpTestData(cls): cls.test_urls = get_all_app_urls(apps.MyAppConfig) # 替换为你自己的AppConfig类 def _test_unauth_redirect(self, url): response = self.client.get(url) # 校验未登录访问自动302跳转到登录页,且携带next参数 self.assertRedirects( response, expected_url=f"{reverse('login_app:login')}?next={url}", target_status_code=200 ) def test_all_urls_redirect_to_login_when_unauth(self): for url in self.test_urls: with self.subTest(url=url): self._test_unauth_redirect(url)
使用注意事项
- 把代码里的应用配置、fixture路径、豁免URL列表替换成你项目对应的实际值即可
- 如果有特殊路径参数不是主键类型、传1会报错的,把对应URL名称加入
EXEMPT_URL_NAMES单独处理即可 - 这套逻辑会自动遍历所有嵌套路由,不需要手动维护URL列表,新增路由时测试会自动覆盖
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

