如何测试 Django QuerySets 是不是相等?

Posted

技术标签:

【中文标题】如何测试 Django QuerySets 是不是相等?【英文标题】:How do I test Django QuerySets are equal?如何测试 Django QuerySets 是否相等? 【发布时间】:2013-07-15 03:13:45 【问题描述】:

我正在尝试测试我的 Django 视图。此视图将 QuerySet 传递给模板:

def merchant_home(request, slug):
  merchant = Merchant.objects.get(slug=slug)
  product_list = merchant.products.all()
  return render_to_response('merchant_home.html',
                            'merchant': merchant,
                            'product_list': product_list,
                            context_instance=RequestContext(request))

和测试:

  def test(self):
    "Merchant home view should send merchant and merchant products to the template"
    merchant = Merchant.objects.create(name='test merchant')
    product = Product.objects.create(name='test product', price=100.00)
    merchant.products.add(product)

    test_client = Client()
    response = test_client.get('/' + merchant.slug)
    # self.assertListEqual(response.context['product_list'], merchant.products.all())
    self.assertQuerysetEqual(response.context['product_list'], merchant.products.all())

编辑 我使用self.assertQuerysetEqual 而不是self.assertListEqual。不幸的是,这仍然不起作用,终端显示: ['<Product: Product object>'] != [<Product: Product object>]


assertListEqual 提出:'QuerySet' object has no attribute 'difference'assertEqual 也不起作用,尽管 self.assertSetEqual(response.context['product_list'][0], merchant.products.all()[0]) 确实通过了。

我认为这是因为 QuerySet 是不同的对象,即使它们包含相同的模型实例。

如何测试两个 QuerySet 是否包含相同的数据?我什至正确地测试了这个?这是我学习 Django 的第四天,所以如果可能的话,我想知道最佳实践。谢谢。

【问题讨论】:

相关:***.com/a/16059121 【参考方案1】:

使用assertQuerysetEqual,它旨在为您比较两个查询集。您需要继承 Django 的 django.test.TestCase 才能在您的测试中使用它。

【讨论】:

太棒了,这很有帮助,尽管现在我的测试因此而失败: AssertionError: [''] != [] 我看到的唯一区别是第一个产品对象周围有引号。它们都是 QuerySet 类【参考方案2】:

使用 pytest 时,另一种但不一定更好的方法可能如下所示(例如,在视图中测试上下文):

all_the_things = Things.objects.all()
assert set(response.context_data['all_the_things']) == set(all_the_things)

这会将其转换为一个集合,可以直接与另一个集合进行比较。请注意 set 的行为,但它可能不是您想要的,因为它会删除重复项并忽略对象的顺序。

【讨论】:

你可能不需要使用set(list())set() 就可以了。【参考方案3】:

默认情况下,assertQuerysetEqual 在第一个参数上使用 repr()。这就是您在查询集比较中遇到字符串问题的原因。

要解决此问题,您可以在 override the transform argument 中使用不使用 repr()lambda 函数:

self.assertQuerysetEqual(queryset_1, queryset_2, transform=lambda x: x)

【讨论】:

我发现这也适用于比较具有相同键和相同查询集值的两个字典:self.assertQuerysetEqual(dict_1, dict_2, transform=lambda x: x)【参考方案4】:

我发现使用self.assertCountEqual(queryset1, queryset2) 也可以解决问题。

【讨论】:

这不会为现有答案添加任何实质性内容。我建议改为支持这些答案。【参考方案5】:

我最终使用maprepr() self.assertQuerysetEqual 调用中查询集中的每个条目解决了这个问题,例如

self.assertQuerysetEqual(queryset_1, map(repr, queryset_2))

【讨论】:

AssertionError: <QuerySet [<Account: Test Account>]> != <map object at 0x10c7f7ac8>【参考方案6】:

我也遇到了同样的问题。 assertQuerysetEqual 的第二个参数需要是作为字符串的预期 repr() 列表。这是 Django 测试套件中的一个示例:

self.assertQuerysetEqual(c1.tags.all(), ["<Tag: t1>", "<Tag: t2>"], ordered=False)

【讨论】:

见***.com/a/14189017/678486(完全公开这是我的答案)。

以上是关于如何测试 Django QuerySets 是不是相等?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Django QuerySets 时使用列表推导而不是 for 循环

如何使用 QuerySets 和 MySql“全文搜索”在多个字段中进行 Django 搜索?

Django QuerySets - 如何注释一个字段但返回另一个字段?

python Django:QuerySets

Django 不返回QuerySets的API

django不返回QuerySets的API