【问题标题】:How do you mock a RelatedManager method in Django?你如何在 Django 中模拟一个 RelatedManager 方法?
【发布时间】:2012-08-26 02:53:36
【问题描述】:

我有一个 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 的调用以引发异常?

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

有人知道怎么做吗?

【问题讨论】:

  • 你在使用 Mock 库吗?你想使用补丁上下文管理器还是装饰器?
  • 如果可以解决这个问题,我很乐意使用模拟库。正如我上面所说,由于相关管理器类的动态声明,以传统方式使用mock.patch 不起作用。

标签: django testing mocking


【解决方案1】:

您不能只将 RelatedManager 设置为模拟对象的原因是 django 已经覆盖了该对象的 set 方法。因此,虽然看起来因为没有投诉而正确设置了模拟,但它实际上默默地将 budget_transactions 设置回了相关管理器。因此,如果您确实需要返回一个模拟对象,那么您需要重写返回 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 将返回一个模拟对象。根据我目前的经验,探索其他选项可能更容易。

【讨论】:

  • 我不得不模拟django.db.models.fields.related.ReverseManyRelatedObjectsDescriptor.__set__,但一般方法相同。
  • 这个问题的当代答案可以在这里找到:stackoverflow.com/a/55910709/2407209
【解决方案2】:

RelatedManager 是一个描述符,必须使用 unittest.PropertyMock 进行模拟

from unittest import patch, MagicMock, PropertyMock, TestCase


class CustomManagerTest(TestCase):
    @patch('app.managers.Transaction.budget_transactions', new_callable=PropertyMock)
    def test_custom_manager_create(self, mock_budget_transactions):
        mock_create = MagicMock()
        mock_budget_transaction.return_value.create = mock_create

        self.assertEqual(mock_create.call_count, 1)

【讨论】:

    猜你喜欢
    • 2012-05-01
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多