You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 14:28:02