9

我有一个 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模拟这个类不起作用,因为它是动态声明的 - 它不能直接导入。

有谁知道如何做到这一点?

4

2 回答 2

9

您不能只将 RelatedManager 设置为模拟对象的原因是 django 已经覆盖了该对象的set方法。因此,虽然看起来因为没有投诉而正确设置了 mock,但它实际上是在默默地设置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 方法,现在所有相关管理器都将返回一个模拟对象。从我迄今为止的经历来看,探索其他选择可能更容易。

于 2014-11-13T01:39:58.353 回答
0

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)
于 2021-12-21T14:24:07.503 回答