2013-04-17 49 views
14

tôi có một cái nhìn rất đơn giản như sauqueryset so sánh trong django testcase

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

Để kiểm tra xem trên trong trường hợp thử nghiệm của tôi tôi có phương pháp sau đây mà lỗi ra.

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 
    # ... 

Lỗi tôi nhận được là AssertionError: False is not true. Tôi đã thử in cả bộ truy vấn và cả hai đều hoàn toàn giống nhau. Tại sao nó trả lại False khi cả hai đối tượng giống hệt nhau? Bất kỳ ý tưởng?

Hiện nay để khắc phục điều này, tôi đang sử dụng một hack khó chịu có độ dài kiểm tra như sau:

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 

Trả lời

19

Đối tượng queryset sẽ không giống hệt nhau nếu họ là kết quả của truy vấn khác nhau ngay cả khi họ có cùng giá trị trong kết quả của họ (so sánh ds1.queryds2.query).

Nếu bạn chuyển đổi các truy vấn thiết lập một danh sách đầu tiên, bạn sẽ có thể làm một so sánh bình thường (giả sử họ có thứ tự sắp xếp cùng tất nhiên):

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

yup, chỉ tìm thấy giải pháp. Cảm ơn. – Amyth

+1

Hoặc self.assertEqual ngắn gọn (danh sách (ds1), danh sách (ds2)) – igniteflow

0

Tìm thấy một giải pháp. Chúng tôi cần chuyển đổi Querysets thành danh sách được sắp xếp trước khi chúng tôi có thể so sánh chúng. Một cái gì đó như sau.

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

thay thế này không cần sắp xếp:

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

Xem assert reference.

Lưu ý: Chỉ dành cho django 1.4+.

+0

Đã thử, nhưng querysets không bằng tất cả thời gian (ngay cả khi chúng giống nhau)! Đã làm việc đó bằng cách sử dụng: 'self.assertQuerysetEqual (qs1, map (repr, qs2), order = False)'. Từ chủ đề này: http://stackoverflow.com/a/14189017/821594 – stalk

+0

@stalk Tôi không thực sự biết tại sao ... nó phải sử dụng 'repr()' để so sánh theo mặc định. Và nếu cả hai quesysets đều bằng nhau thì repr được cho là giống nhau, đúng không? –

+2

Nhìn vào [docs] (https://docs.djangoproject.com/en/1.5/topics/testing/overview/#django.test.TestCase.assertQuerysetEqual) tôi nghĩ, ví dụ của bạn sẽ hoạt động. Nhưng nó không ... Có vẻ như 'repr' func chỉ được áp dụng cho queryset không có danh sách đầu tiên, và đối với danh sách thứ hai nó phải được applided một cách rõ ràng. Với django 1.4.5: 'qs1 = M.objects.all(); qs2 = M.objects.all() # (giống nhau) ',' self.assertQuerysetEqual (qs1, list (qs2), order = False) '<- failed; 'self.assertQuerysetEqual (qs1, map (repr, qs2), thứ tự = False)' <- passes; – stalk