在使用Django DirtyFields的测试中使用fixture进行问题

时间:2013-04-22 22:17:23

标签: django unit-testing fixtures django-signals

如果您正在实施Django DirtyFields,在测试中使用灯具时是否存在已知问题?

我们将django_nose的{​​{1}}用于灯具和封面。我打算尝试实施NoseTestSuiteRunner来执行一些自定义django-dirtyfields活动。我做的唯一改变如下:

post_save()

我们使用此from dirtyfields import DirtyFieldsMixin class BaseModel(DirtyFieldsMixin, models.Model): """ Base model """ class Meta: abstract = True 来扩展我们的大多数其他模型。添加BaseModel会导致我们的测试死亡,并出现以下重复错误:

DirtyFieldsMixin

据我所知,每当夹具试图加载时都会发生此错误。有什么想法吗? Problem installing fixture '/home/ricomoss/workspace/project/settings/../apps/contracts/fixtures/test_contracts_data.json': Traceback (most recent call last): File "/home/ricomoss/.virtualenvs/project/local/lib/python2.7/site-packages/django/core/management/commands/loaddata.py", line 193, in handle for obj in objects: File "/home/ricomoss/.virtualenvs/project/local/lib/python2.7/site-packages/django/core/serializers/json.py", line 47, in Deserializer raise DeserializationError(e) DeserializationError: Field matching query does not exist. 不包含任何可能导致我的灯具需要更新的新字段(更不用说必需的字段)。

编辑1: 看来我的问题与Django中的fixtures/signal问题直接相关。如果我们查看DirtyFieldsMixin定义,我们可以立即看到问题所在(我已经验证了这一点):

DirtyFieldsMixin

具体地,

class DirtyFieldsMixin(object):
    def __init__(self, *args, **kwargs):
        super(DirtyFieldsMixin, self).__init__(*args, **kwargs)
        post_save.connect(
            self._reset_state, sender=self.__class__,
            dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format(
                self.__class__.__name__))
        self._reset_state()

    def _reset_state(self, *args, **kwargs):
        self._original_state = self._as_dict()

    def _as_dict(self):
        return dict([(f.name, getattr(self, f.name)) for f in
                     self._meta.local_fields if not f.rel])

    def get_dirty_fields(self):
        new_state = self._as_dict()
        return dict([(key, value) for key, value in
                     self._original_state.iteritems()
                     if value != new_state[key]])

    def is_dirty(self):
        # in order to be dirty we need to have been saved at least once, so we
        # check for a primary key and we need our dirty fields to not be empty
        if not self.pk:
            return True
        return {} != self.get_dirty_fields()

我尝试按照给定的solution创建一个装饰器。我要么错误地实现装饰器,要么就这种情况不起作用。我对它在这种情况下的使用感到有点困惑。

我会将装饰器放在post_save.connect(self._reset_state, sender=self.__class__, dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format( self.__class__.__name__))

上吗?
__init__

在这种情况下我仍然失败了。有什么建议吗?

编辑2: 我也尝试将装饰器添加到@utils.disable_for_loaddata def __init__(self, *args, **kwargs): super(DirtyFieldsMixin, self).__init__(*args, **kwargs) post_save.connect( self._reset_state, sender=self.__class__, dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format( self.__class__.__name__)) self._reset_state() 方法中。这也不起作用。

_reset_state

编辑3: 我想我正在取得进展。我将装饰器的@utils.disable_for_loaddata def _reset_state(self, *args, **kwargs): self._original_state = self._as_dict() 部分直接移到inspect.stack()(正好在__init__电话上方)。

我正在接受其他活动,但我的测试套件仍未正确运行。我不再收到loaddata错误。

post_save

编辑4: 我已经决定要为这个过程编写自己的mixin。我不相信我需要为我的目的使用信号。因此,我将覆盖def __init__(self, *args, **kwargs): super(DirtyFieldsMixin, self).__init__(*args, **kwargs) import inspect for fr in inspect.stack(): if inspect.getmodulename(fr[1]) == 'loaddata': return post_save.connect( self._reset_state, sender=self.__class__, dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format( self.__class__.__name__)) self._reset_state() 方法并以特殊方式处理此方法。

2 个答案:

答案 0 :(得分:0)

我能够实现一个我不喜欢的黑客攻击。如果有人提出了更好的解决方案,我很乐意看到它。

基本上我做了建议解决方案的装饰器所做的事情,但是在堆栈上查找任何测试用例。

class DirtyFieldsMixin(object):
    def __init__(self, *args, **kwargs):
        super(DirtyFieldsMixin, self).__init__(*args, **kwargs)

        # Hack code used to avoid unittest failures due to the following
        # post_save.connect() call.
        import inspect
        for fr in inspect.stack():
            if inspect.getmodulename(fr[1]) == 'testcases':
                return
        post_save.connect(
            self._reset_state, sender=self.__class__,
            dispatch_uid='{}-DirtyFieldsMixin-sweeper'.format(
                self.__class__.__name__))
        self._reset_state()

答案 1 :(得分:0)

撤销继承应该让你无需更改即可启动并运行。

class BaseModel(models.Model, DirtyFieldsMixin):