2013-04-17 12 views
14

Ich habe eine sehr einfache Sicht haben wie folgtVergleich querysets in django Testfall

def simple_view(request): 
    documents = request.user.document_set.all() 
    return render(request, 'simple.html', {'documents': documents}) 

Um die obige Ansicht in meinem Testfall zu testen Ich habe die folgende Methode, die Fehler aus.

Class SomeTestCase(TestCase): 
    # ... 
    def test_simple_view(self): 
     # ... some other checks 
     docset = self.resonse.context['documents'] 
     self.assertTrue(self.user.document_set.all() == docset) # This line raises an error 
    # ... 

Der Fehler, den ich bekomme, ist AssertionError: False is not true. Ich habe versucht, beide Abfrage-Sets zu drucken und beide sind absolut identisch. Warum würde es False zurückgeben, wenn beide Objekte identisch sind? Irgendwelche Ideen ?

Zeit, dies zu überwinden, ich bin ein gemeiner Hack zu prüfen Längen wie folgt verwendet:

ds1, ds2 = self.response.context['documents'], self.user.document_set.all() 
self.assertTrue(len([x for x in ds1 if x in ds2]) == len(ds1) == len(ds2)) # Makes sure each entry in ds1 exists in ds2 

Antwort

19

Die queryset Objekte nicht identisch sein, wenn sie das Ergebnis verschiedener Abfragen sind, auch wenn sie die gleichen Werte haben in ihrem Ergebnis (vergleiche ds1.query und ds2.query).

Wenn Sie die Abfrage auf eine Liste zuerst konvertieren, sollten Sie in der Lage sein, einen normalen Vergleich zu tun (vorausgesetzt, sie die gleiche Sortierreihenfolge natürlich haben):

self.assertEqual(list(ds1), list(ds2)) 
+0

yup, gerade die Lösung gefunden. Vielen Dank. – Amyth

+1

Oder etwas prägnanter self.assertEqual (list (ds1), list (ds2)) – igniteflow

0

eine Lösung gefunden. Wir müssen Querysets in sortierte Listen konvertieren, bevor wir sie vergleichen können. Etwas wie folgt.

Class SomeTestCase(TestCase): 
    # ... 
    def test_simple_view(self): 
     # ... some other checks 
     docset1 = self.resonse.context['documents'] 
     docset2 = self.user.document_set.all() 
     self.assertTrue(list(sorted(docset1)) == len(sorted(docset))) 
    # ... 
6

Diese Alternative muss nicht Sortierung:

self.assertQuerysetEqual(qs1, list(qs2), ordered=False) 

Siehe assert reference.

Hinweis: Nur für Django 1.4+.

+0

Versucht dies, aber querysets sind nicht gleich die ganze Zeit (auch wenn sie gleich sind)! Habe es funktioniert mit: 'self.assetQuerysetEqual (qs1, map (repr, qs2), geordnete = False)'. Von diesem Thread: http://stackoverflow.com/a/14189017/821594 – stalk

+0

@stalk Ich weiß nicht wirklich warum ... es soll 'repr()' verwenden, um standardmäßig zu vergleichen. Und wenn beide Quesets gleich sind, wird erwartet, dass der Ausdruck derselbe ist, oder? –

+2

Mit Blick auf [Docs] (https://docs.djangoproject.com/en/1.5/topics/testing/overview/#django.test.TestCase.assertQuerysetEqual) dachte ich, dass Ihr Beispiel funktioniert. Aber es sieht nicht so aus ... Sieht so aus, als würde 'repr' func nur auf das erste Nicht-Listen-Abfrage-Set angewendet, und für die zweite Liste muss es explizit angewendet werden. Mit Django 1.4.5: 'qs1 = M.objects.all(); qs2 = M.objects.all() # (das gleiche) ',' self.asserQuerysetEqual (qs1, list (qs2), ordered = False) '<- fehlschlägt; 'self.asserQuerysetEqual (qs1, map (repr, qs2), geordnet = Falsch)' <- geht; – stalk