我有以下功能:
import unittest
from unittest import mock
def get_payments(order):
return order.payments.filter(status='complete').order_by('-date_added)
我想模拟filter
方法和order_by
来检查调用的参数。
我试过了:
class TestPayments(unittest.TestCase):
@mock.patch('path.Order.payments.filter.order_by')
@mock.patch('path.Order.payments.filter')
def test_get_payments(self, mock1, mock2):
mock1.assert_called_with(status='complete')
mock2.assert_called_with('-date_added')
我试过的另一个模拟:
@mock.patch('path.Payment.objects.filter.order_by')
@mock.patch('path.Payment.objects.filter')
@mock.patch('path.Order.payments.objects.filter.order_by')
@mock.patch('path.Order.payments.objects.filter')
在最后两次嘲笑中,我遇到path.Order
不存在的错误。
我已经使用直接模拟来查找Payment.objects.filter()
这样的查询并且正在运行,但是从Order
这样的相关模型开始我失败了。
Order
和Payment
之间的关系是您所期望的,一对多。
答案 0 :(得分:3)
通过模拟对象我解决了这个问题。
order = MagicMock(side_effect=Order())
order.payments.filter.return_value = MagicMock(side_effect=Payment.objects.filter(id=0))
order.payments.filter.return_value.order_by.return_value = [Payment()]
order.payments.filter.assert_called_with(status='complete')
order.payments.filter.return_value.order_by.assert_called_with('-date_updated')
答案 1 :(得分:1)
要解释这里发生的事情:filter()
,exclude()
,order_by()
等QuerySet方法返回一个QuerySet,这就是它们可以被链接的原因。
您首先尝试修补方法,就好像它们位于包层次结构中一样。你最终做的不是修补方法,而是模拟每个链式方法的返回值,这就是它的完成方式。
不幸的是,没有太多关于此的文档。当我遇到这个问题时,我有一些帮助我的stackoverflow答案,但我似乎无法再找到它们。
类似问题(答案并未真正提供解释):
有些库可能会对您有所帮助:mock-django提供了一个ORM模拟类。他们对mocking QuerySet methods的态度非常有趣。我个人认为测试Django模型非常有用的是Model Mommy,因为它可以帮助你创建简单的模型模型。