如何使用pytest测试Django REST Framework中基于环境变量拆分的API路由
如何使用pytest测试Django REST Framework中基于环境变量拆分的API路由
嘿,我帮你分析下问题所在,顺便给你解决办法!
首先先提个容易忽略的小bug:你主urls.py里的判断条件写错了!elif config.settings == CUSTOM:应该改成elif config.settings.MODE == CUSTOM——少了.MODE,这会导致即使你把环境变量设为custom,代码也不会走到custom路由的分支,先把这个fix掉再说。
接下来是测试的核心问题:你的主urls.py里的if/elif路由判断是在模块第一次被导入的时候执行的,而pytest运行测试时,这个模块早就加载完毕了。所以你后面用fixture或者override_settings修改settings.MODE,根本不会触发路由的重新计算,路由列表已经固定成测试启动时的那个了。
给你两种可行的解决思路:
方法一:测试时手动刷新路由配置
既然路由是在模块加载时生成的,那我们可以在修改settings.MODE之后,手动清除URL缓存并重新加载主urls模块,让它重新生成路由列表。
你可以这么写测试代码:
import importlib from django.conf import settings from django.urls import clear_url_caches import pytest @pytest.fixture def set_mode_custom(settings): # 设置为custom模式 settings.MODE = "custom" # 清除Django的URL缓存 clear_url_caches() # 重新加载主urls模块,触发路由重新计算 main_urls = importlib.reload(__import__("your_project_name.urls").urls) # 更新全局的urlpatterns from django.conf.urls import urlpatterns urlpatterns[:] = main_urls.urlpatterns def test_custom_example(set_mode_custom, client): resp = client.get("/custom/v1/custom-example/") assert resp.status_code == 200 # 测试normal模式同理 @pytest.fixture def set_mode_normal(settings): settings.MODE = "normal" clear_url_caches() importlib.reload(__import__("your_project_name.urls").urls) def test_normal_example(set_mode_normal, client): resp = client.get("/normal/v1/normal-example/") assert resp.status_code == 200
记得把your_project_name替换成你实际的Django项目名称哦。
方法二:重构路由逻辑(更优雅的长期方案)
把路由判断放在模块级别不够灵活,我们可以把路由生成逻辑封装成一个函数,让代码结构更清晰,也方便后续维护:
修改主urls.py:
from django.urls import path, include from django.conf import settings def get_api_urlpatterns(): NORMAL = "normal" CUSTOM = "custom" urlpatterns = [] if settings.MODE == NORMAL: urlpatterns.append(path("normal/v1/", include("api.normal.v1.urls"))) elif settings.MODE == CUSTOM: urlpatterns.append(path("custom/v1/", include("api.custom.v1.urls"))) return urlpatterns # 基础路由(比如admin、静态文件等) base_urlpatterns = [ # path('admin/', admin.site.urls), # 其他非API路由 ] # 合并路由 urlpatterns = base_urlpatterns + get_api_urlpatterns()
然后测试时还是用方法一的思路:修改settings后清除缓存并重新加载urls模块,这样不管是生产环境切换环境变量,还是测试中动态修改settings,都能正确切换路由了。
备注:内容来源于stack exchange,提问作者Joey Fran
相关产品推荐
相关产品推荐

