我想做的事
我正在尝试编写单元测试来检查我的正则表达式是否正确构造:
# mediamanager/models.py
import re
from django.conf import settings
filetypes_re = {}
for key, exts in settings.MM_FILETYPES.items():
filetypes_re[key] = re.compile(r'({})'.format('|'.join(exts)))
注意:实际上,我根本不知道我为什么要编写这个单元测试,因为这段代码非常简单……但这不是重点。
如您所见,最终的正则表达式取决于用户可以设置的变量 settings.MM_FILETYPES。我需要测试特定的输入,对于这种情况,Django 提供了装饰器 @override_settings ,它临时覆盖设置值:
# mediamanager/tests.py
import unittest
from django.test.utils import override_settings
from mediamanager.models import (filetypes_re, …) # import everything we want to test
class ModelsTestCase(unittest.TestCase):
@override_settings(MM_FILETYPES={'image': ['jpg', 'png', 'gif'],
'document': ['pdf', 'txt'],
'audio': ['mp3', 'wav']})
def test_filetype_re(self):
filetypes_re_exp = {'image': '(jpg|png|gif)',
'document': '(pdf|txt)',
'audio': '(mp3|wav)'}
for key, value in filetypes_re_exp.items():
self.assertEqual(value, filetypes_re[key].pattern)
不幸的是,这个测试没有通过。模块 mediamanager.models 在设置被覆盖之前加载,因此 filetypes_re 使用旧设置编译。我需要(以某种方式)重新加载它以使新设置生效。
问题
我以这种方式更改了单元测试:
@override_settings(MM_FILETYPES={'image': ['jpg', 'png', 'gif'],
'document': ['pdf', 'txt'],
'audio': ['mp3', 'wav']})
def test_filetype_re(self):
import mediamanager.models # obtaining module object from sys.modules have the same result
reload(mediamanager.models)
filetypes_re = mediamanager.models.filetypes_re
filetypes_re_exp = {'image': '(jpg|png|gif)',
'document': '(pdf|txt)',
'audio': '(mp3|wav)'}
for key, value in filetypes_re_exp.items():
self.assertEqual(value, filetypes_re[key].pattern)
并且测试通过了。但可能是因为我从 mediamanager.models 模块导入了其他对象,这个测试用例中的其他测试失败了。不是全部,只有两个(这很奇怪)。编辑:一点也不奇怪。只有在 test_filetyes_re 和 reload() 调用之后运行的测试才会失败。
问题
如何以以下方式“重新加载”模块 mediamanager.models:
- filetypes_re 使用新设置进行评估?
- 从同一模型导入的所有其他对象不受影响?
我是否应该仅仅因为重新加载后变得不稳定而重写一段代码(我的意思是来自 mediamanager.models 的其他那些在重新加载后未通过测试的对象)?我读过一些关于重新加载模块的文章,通常这不是一个好主意。
有没有更好的方法来定义模块级对象,比如这个正则表达式,使测试更容易?