我正在为Django应用程序编写测试,但我的测试之一失败了,而一个奇怪的错误是assertEqual
比较失败,即使两个查询集中的对象都匹配。
测试很大,所以我写了一个小测试来重现错误:
class StrangeBehaviorTest(TestCase):
def test_init(self):
purchase = ArrangementPurchaseFactory()
self.assertTrue(purchase)
self.assertTrue(purchase.arrangement_period)
self.assertEqual(ArrangementPurchase.objects.count(), 1)
fetched = ArrangementPurchase.objects.filter(
id=1)
self.assertEqual(fetched.first().id, purchase.id)
self.assertEqual(fetched.first(), purchase)
self.assertEqual(fetched, ArrangementPurchase.objects.filter(
id=1
))
运行此测试时,最后一个断言失败并显示以下错误:
AssertionError: <QuerySet [<ArrangementPurchase: 1 : user_0 - Profound bandwidth-monitored pricing structure (vanaf 2019-04-24)>]> != <QuerySet [<ArrangementPurchase: 1 : user_0 - Profound bandwidth-monitored pricing structure (vanaf 2019-04-24)>]>
我已验证我的ArrangementPurchaseFactory
是DjangoModelFactory
的子类(如下所示)
class ArrangementPurchaseFactory(factory.django.DjangoModelFactory):
class Meta:
model = arrangement_models.ArrangementPurchase
user = factory.SubFactory(UserFactory)
arrangement_period = factory.SubFactory(ArrangementPeriodFactory)
purchase_date = factory.LazyFunction(
lambda: timezone.now() - datetime.timedelta(days=10)
)
expire_date = factory.LazyFunction(
lambda: timezone.now() + datetime.timedelta(days=30)
)
tenant_demo_purchase = False
price_paid = factory.LazyFunction(lambda: Decimal(0))
linked_order_id = factory.Faker('sha1')
rabo_purchase_pending = False
据我所知,两个查询集中的对象都存在于数据库中(该对象具有id值),fetched
查询的pk值与现有的purchase.id
那为什么测试失败了?有人知道我在想什么吗?
答案 0 :(得分:2)
这是因为尽管这些querySet的值相等,但实际上它们是不同的对象。
您需要的是assertQuerysetEqual
。从文档中:
TransactionTestCase.assertQuerysetEqual (qs,值,transform = repr, ordered = True,msg = None)[https://docs.djangoproject.com/en/2.2/topics/testing/tools/]断言查询集qs返回a 值的特定列表。
比较qs和值的内容是使用 功能变换;默认情况下,这意味着每个的repr() 比较值。如果repr()不存在,则可以使用任何其他可调用对象 提供独特或有用的比较。
默认情况下,比较也取决于顺序。如果qs没有 提供隐式排序,您可以将ordered参数设置为 否,将比较结果转换为集合。 比较。如果顺序未定义(如果给定的q不排序 并且比较是针对多个订购值的) 引发ValueError。
发生错误时的输出可以使用msg参数自定义。
答案 1 :(得分:1)
Django在QuerySet
实例之间不提供任何特定的相等性比较(请参见代码:https://github.com/django/django/blob/master/django/db/models/query.py#L185)。
如果未提供自定义__eq__
方法,Python将退回比较内存中的对象地址。
QuerySet
的两个不同实例即使使用相同的参数构建,也将具有不同的地址,并且比较不相等。
如果要比较查询集的内容(即数据库中对象的列表),则必须对其进行评估,例如将其转换为列表:
self.assertEqual(list(fetched), list(ArrangementPurchase.objects.filter(id=1)))
使用此方法,Python将比较列表,其__eq__
方法比较列表的内容而不是它们的内存地址。
注意:如果列表中有多个项目,则必须考虑订购。
另一种选择是使用assertQuerysetEqual
:https://docs.djangoproject.com/en/2.2/topics/testing/tools/#django.test.TransactionTestCase.assertQuerysetEqual