你如何模拟Django中的RelatedManager方法?

时间:2012-08-31 09:41:45

标签: django testing mocking

我有一个Django模型的客户经理,该模型会覆盖create方法以保存一些相关对象:

class CustomManager(models.Manager):
    def create(self, amount, user, description):
        txn = self.get_query_set().create(user, description)
        txn.budget_transactions.create(amount)
        return txn

我的问题是:如何模拟对txn.budget_transactions.create的调用以引发异常?

budget_transactions对象的txn属性是django.db.models.fields.related.RelatedManager的实例。使用mock.patch来模拟这个类不起作用,因为它是动态声明的 - 它无法直接导入。

有谁知道怎么做?

1 个答案:

答案 0 :(得分:6)

您不能将RelatedManager设置为模拟对象的原因是因为django已覆盖对象上的 set 方法。因此,虽然看起来模拟设置正确,因为没有抱怨,但它实际上是静默地将budget_transactions设置回RelatedManager。因此,如果您确实需要返回模拟,那么您将需要覆盖返回RelatedManager的 get 方法,并返回一个模拟对象。

应该最终看起来像:

@mock.patch('django.db.models.fields.related.ForeignRelatedObjectsDescriptor.__get__')
def test_campaign_cancel(self, mock_manager):
    mock_manager.return_value = mock.MagicMock()
    mock_manager.return_value.create = Exception('Boom!')

话虽如此,这种方法存在许多缺陷,因为它将覆盖核心django方法,现在 ALL RelatedManagers将返回一个模拟对象。根据我迄今为止所经历的情况,探索其他选择可能更容易。