How do I test Django QuerySets are equal?

孤人 提交于 2019-11-27 23:01:11

问题


I am trying to test my Django views. This view passes a QuerySet to the template:

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))

and test:

  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())

EDIT I am using self.assertQuerysetEqual instead of self.assertListEqual. Unfortunately this still doesn't work, and the terminal displays this: ['<Product: Product object>'] != [<Product: Product object>]


assertListEqual raises: 'QuerySet' object has no attribute 'difference' and assertEqual does not work either, although self.assertSetEqual(response.context['product_list'][0], merchant.products.all()[0]) does pass.

I assume this is because the QuerySets are different objects even though they contain the same model instances.

How do I test that two QuerySets contain the same data? I am even testing this correctly? This is my 4th day learning Django so I would like to know best practices, if possible. Thanks.


回答1:


Use assertQuerysetEqual, which is built to compare the two querysets for you. You will need to subclass Django's django.test.TestCase for it to be available in your tests.




回答2:


By default assertQuerysetEqual uses repr() on the first argument. This is why you were having issues with the strings in the queryset comparison.

To work around this you can override the transform argument with a lambda function that doesn't use repr():

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



回答3:


I just had the same problem. The second argument of assertQuerysetEqual needs to be a list of the expected repr()s as strings. Here is an example from the Django test suite:

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



回答4:


I ended up solving this issue using map to repr() each entry in the queryset inside the self.assertQuerysetEqual call, e.g.

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



回答5:


An alternative, but not necessarily better, method might look like this (testing context in a view, for example) when using pytest:

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

This converts it to a list, then a set, which is directly comparable with another set. Be careful with the behavior of set though, it might not be exactly what you want since it will remove duplicates.




回答6:


I found that using self.assertCountEqual(queryset1, queryset2) also solves the issue.



来源:https://stackoverflow.com/questions/17685023/how-do-i-test-django-querysets-are-equal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!