来自相关对象的 Django 单元测试模拟查询集
Django unit test mock queryset from related object
我有以下功能:
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
之间的关系如您所料,一对多。
通过模拟对象我解决了这个问题。
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')
解释一下这里发生了什么:QuerySet 方法,如 filter()
、exclude()
、order_by()
等。return 一个 QuerySet,这就是它们可以链接的原因。
您首先尝试的是尝试修补方法,就好像它们在包层次结构中一样。您最终做的不是修补方法,而是模拟每个链接方法的 return 值,这就是它的完成方式。
不幸的是,关于这方面的文档不多。当我 运行 解决这个问题时,我得到了一些对我有帮助的 Whosebug 答案,但我似乎再也找不到它们了。
类似问题(答案并没有真正提供解释):
Django ORM - mock values().filter() chain
Mocking a Django Queryset in order to test a function that takes a queryset
有些库可以帮助您:mock-django provides an ORM mocking class. Their approach to mocking QuerySet methods is quite interesting. What I personally found very useful for testing Django models is Model Mommy,因为它可以帮助您创建简单的模型模拟。
我有以下功能:
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
之间的关系如您所料,一对多。
通过模拟对象我解决了这个问题。
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')
解释一下这里发生了什么:QuerySet 方法,如 filter()
、exclude()
、order_by()
等。return 一个 QuerySet,这就是它们可以链接的原因。
您首先尝试的是尝试修补方法,就好像它们在包层次结构中一样。您最终做的不是修补方法,而是模拟每个链接方法的 return 值,这就是它的完成方式。
不幸的是,关于这方面的文档不多。当我 运行 解决这个问题时,我得到了一些对我有帮助的 Whosebug 答案,但我似乎再也找不到它们了。
类似问题(答案并没有真正提供解释):
Django ORM - mock values().filter() chain
Mocking a Django Queryset in order to test a function that takes a queryset
有些库可以帮助您:mock-django provides an ORM mocking class. Their approach to mocking QuerySet methods is quite interesting. What I personally found very useful for testing Django models is Model Mommy,因为它可以帮助您创建简单的模型模拟。