Python - 重新加载模块级对象

时间:2012-07-23 19:03:12

标签: python django unit-testing testing

我想做什么

我正在尝试编写单元测试来检查我的正则表达式是否构造正确:

# 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:

    使用新设置评估
  1. filetypes_re?
  2. 从同一模型导入的所有其他对象不受影响?
  3. 我应该只重写一段代码,因为它在重新加载后变得不稳定(我的意思是来自mediamanager.models的其他那些在重新加载后没有通过测试的对象)?我已经阅读了一些关于重新加载模块的文章,通常这不是一个好主意。

    有没有更好的方法来定义模块级对象,比如这个正则表达式,以使测试更容易?

1 个答案:

答案 0 :(得分:0)

有两种方法。脱离我的头顶:

# mediamanager/models.py

import re

from django.conf import settings

def get_filetypes_re(mm_filetypes=settings.MM_FILETYPES):
    filetypes_re = {}
    for key, exts in settings.MM_FILETYPES.items():
    filetypes_re[key] = re.compile(r'({})'.format('|'.join(exts)))
    return filetypes_re 

和你的考试:

MM_FILETYPES={'image': ['jpg', 'png', 'gif'],
                        'document': ['pdf', 'txt'],
                        'audio': ['mp3', 'wav']})

def test_filetype_re(self):
    filetypes_re = mediamanager.models.get_filetypes_re(mm_filetypes=MM_FILETYPES)
    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)