Django测试发现异常:admin/models模块被误识别为测试用例
问题
执行./manage.py test时触发如下错误:
... test_create_default_action_with_deadline (masoon.anomalies.tests.anomaly.AnomalyCreateDefaultAction) ... ok masoon.actions.admin (unittest.loader._FailedTest) ... ERROR masoon.actions.models (unittest.loader._FailedTest) ... ERROR masoon.anomalies.models (unittest.loader._FailedTest) ... ERROR ... ====================================================================== ERROR: masoon.actions.admin (unittest.loader._FailedTest) ---------------------------------------------------------------------- ImportError: Failed to import test module: masoon.actions.admin Traceback (most recent call last): File "/usr/lib/python3.10/unittest/loader.py", line 470, in _find_test_path package = self._get_module_from_name(name) File "/usr/lib/python3.10/unittest/loader.py", line 377, in _get_module_from_name __import__(name) File "/home/vahid/project/py/django/masoon/actions/admin/__init__.py", line 1, in <module> from .actions import ActionsAdmin File "/home/vahid/project/py/django/masoon/actions/admin/actions.py", line 8, in <module> class ActionsAdmin(AbstractBaseAdmin): File "/home/vahid/project/py/django/masoon/.venv/lib/python3.10/site-packages/django/contrib/admin/decorators.py", line 100, in _model_admin_wrapper admin_site.register(models, admin_class=admin_class) File "/home/vahid/project/py/django/masoon/.venv/lib/python3.10/site-packages/django/contrib/admin/sites.py", line 126, in register raise AlreadyRegistered(msg) django.contrib.admin.sites.AlreadyRegistered: The model Action is already registered with 'actions.ActionsAdmin'.
实际问题并非Admin重复注册,而是unittest错误地将admin、models模块识别为测试用例并尝试加载执行。
项目目录结构:
... ├── actions │ ├── admin │ │ ├── action_report.py │ │ ├── actions.py │ │ ├── answer.py │ │ ├── __init__.py │ ├── api │ | ├── ... │ ├── tests │ | ├── actions.py │ | ├── answers.py ... │ ├── apps.py │ ├── __init__.py │ ├── models │ │ ├── action.py │ │ ├── action_report.py │ │ ├── answer.py │ │ ├── __init__.py ├── infrastructure │ ├── asgi.py │ │ ... │ ├── urls.py │ └── wsgi.py ├──settings ... │ ├── apps.py │ ├── files.py │ ├── __init__.py │ ├── logging.py │ ├── main.py │ ├── middlewares.py ... ├── manage.py ...
特殊现象:执行./manage.py test modulname.tests时所有测试正常通过,Django不会把models/admin模块识别为测试用例。
相关模块的__init__.py内容:
- settings模块:
... from .apps import * from .middlewares import * from .drf import * ...
- 测试、models等模块示例:
from .anomaly import AnomalyCreateDefaultAction, AnomalyAPITest
疑问:为何unittest会把admin类和model类识别为测试用例并尝试运行?
原因分析
Django的测试发现基于Python标准库unittest的规则:
- 默认情况下,
unittest会递归扫描项目,除了找命名为test*.py的文件,还会把包含__init__.py的包当作潜在测试包——如果这些包的模块里有继承unittest.TestCase的类,就会被当作测试用例加载。 - 你的
models、admin模块的__init__.py导入了类,加载时触发了Admin注册逻辑;同时,测试模块的__init__.py导入了测试类,可能通过项目的导入路径被models/admin模块间接引用到,导致unittest误判这些非测试包为测试包。 - 当你指定
modulname.tests时,测试范围被限定到tests子包内,unittest只会扫描该路径下的内容,不会触及admin、models模块,因此不会触发错误。
解决方案
明确指定测试路径:
日常测试直接限定测试模块,比如:./manage.py test actions.tests anomalies.tests或者用通配符批量指定所有tests目录:
./manage.py test */tests清理不必要的导入:
- 检查
models、admin模块的__init__.py,只保留必要的模型/Admin类导入,移除任何间接关联测试类的导入。 - 测试模块的
__init__.py仅导入测试相关类,避免非测试模块间接引用到测试类。
- 检查
自定义测试发现规则:
在项目根目录创建unittest.cfg文件,排除非测试目录:[unittest] discover = True pattern = test*.py top_level_dir = . exclude = admin models执行测试时指定配置文件:
./manage.py test --config=unittest.cfg
内容的提问来源于stack exchange,提问作者vahidtwo
相关产品推荐
相关产品推荐

