2013-08-27 37 views
17

Tôi biết rằng, khi thực hiện assertEqual trên từ điển, assertDictEqual được gọi. Tương tự, assertEqual theo trình tự sẽ thực hiện assertSequenceEqual.Làm thế nào để đạt được assertDictEqual với assertSequenceEqual được áp dụng cho các giá trị

Tuy nhiên, khi assertDictEqual đang so sánh các giá trị, có vẻ như không sử dụng số assertEqual và do đó assertSequenceEqual không được gọi.

Hãy xem xét các từ điển đơn giản sau đây:

lst1 = [1, 2] 
lst2 = [2, 1] 

d1 = {'key': lst1} 
d2 = {'key': lst2} 

self.assertEqual(lst1, lst2) # True 
self.assertEqual(d1, d2) # False >< 

Làm thế nào tôi có thể kiểm tra từ điển như d1d2 mà bình đẳng của họ là đúng cách so sánh, bởi đệ quy áp dụng assertEqual -like ngữ nghĩa cho các giá trị?

Tôi muốn tránh sử dụng mô-đun bên ngoài (như được đề xuất in this question) nếu có thể, trừ khi chúng là tiện ích mở rộng django gốc.


EDIT

Về cơ bản, những gì tôi theo đuổi là tích hợp sẵn trong phiên bản này:

def assertDictEqualUnorderedValues(self, d1, d2): 
    for k,v1 in d1.iteritems(): 
     if k not in d2: 
      self.fail('Key %s missing in %s'%(k, d2)) 

     v2 = d2[k] 

     if isinstance(v1, Collections.iterable) and not isinstance(v1, basestring): 
      self.assertValuesEqual(v1, v2) 
     else: 
      self.assertEqual(v1, v2) 

Vấn đề với mã trên là các thông báo lỗi là không đẹp như các khẳng định được xây dựng, và có lẽ các trường hợp cạnh tôi đã bỏ qua (như tôi vừa viết ra khỏi đầu của tôi).

+2

Với mô-đun 'unittest', 'self.assertEqual (lst1, lst2)' không đúng -> 'AssertionError: Danh sách khác: [1, 2]! = [2, 1]'. – martineau

+0

@martineau - lỗi của tôi; Tôi đã đọc sai phần đó của tài liệu. Tôi đang tìm kiếm một tương đương với 'assertItemsEqual' thay vì' assertSequenceEqual' – sapi

+1

Vâng, nếu bạn tạo 'lst1' và' lst2' giống như vậy thì 'assertEqual' đầu tiên thành công, thì cái thứ hai cũng sẽ thành công. – martineau

Trả lời

4

Phương thức TestCase.assertEqual() gọi lớp 'assertDictEqual() cho dicts, vì vậy chỉ cần ghi đè lên đó trong dẫn xuất lớp con của bạn. Nếu bạn chỉ sử dụng các phương thức assertXXX khác trong phương pháp, thông báo lỗi sẽ gần giống như các xác nhận tích hợp - nhưng nếu bạn không thể cung cấp đối số từ khóa msg khi bạn gọi cho chúng để kiểm soát nội dung được hiển thị.

import collections 
import unittest 

class TestSOquestion(unittest.TestCase): 

    def setUp(self): 
     pass # whatever... 

    def assertDictEqual(self, d1, d2, msg=None): # assertEqual uses for dicts 
     for k,v1 in d1.iteritems(): 
      self.assertIn(k, d2, msg) 
      v2 = d2[k] 
      if(isinstance(v1, collections.Iterable) and 
       not isinstance(v1, basestring)): 
       self.assertItemsEqual(v1, v2, msg) 
      else: 
       self.assertEqual(v1, v2, msg) 
     return True 

    def test_stuff(self): 
     lst1 = [1, 2] 
     lst2 = [2, 1] 

     d1 = {'key': lst1} 
     d2 = {'key': lst2} 

     self.assertItemsEqual(lst1, lst2) # True 
     self.assertEqual(d1, d2) # True 

if __name__ == '__main__': 
    unittest.main() 

Output:

> python unittest_test.py 
. 
----------------------------------------------------------------------> 
Ran 1 test in 0.000s 

OK 

> 
+1

Tôi không thể đảm bảo thứ tự của danh sách. Các bài kiểm tra là dành cho một khung công tác django, và tôi không thể dựa vào thứ tự các truy vấn cơ sở dữ liệu giống nhau giữa các tập kiểm tra và kết quả mong đợi. Tất cả những gì tôi quan tâm là API cung cấp cho tôi các giá trị chính xác trong * một số thứ tự *. – sapi

+0

OK, nhưng tôi vẫn không hiểu tại sao/làm thế nào bạn mong đợi 'assertEqual đầu tiên (lst1, lst2)' là True trong mã của bạn. – martineau

+0

Giải pháp này không hoạt động trên danh sách + danh sách lồng nhau sâu sắc. Các giải pháp dựa trên phân loại nào. – Federico

7

Thay vì trọng assertDictEqual, tại sao bạn không đệ quy loại dicts của bạn đầu tiên?

def deep_sort(obj): 
    """ 
    Recursively sort list or dict nested lists 
    """ 

    if isinstance(obj, dict): 
     _sorted = {} 
     for key in sorted(obj): 
      _sorted[key] = deep_sort(obj[key]) 

    elif isinstance(obj, list): 
     new_list = [] 
     for val in obj: 
      new_list.append(deep_sort(val)) 
     _sorted = sorted(new_list) 

    else: 
     _sorted = obj 

    return _sorted 

Sau đó, sắp xếp, và sử dụng assertDictEqual bình thường:

dict1 = deep_sort(dict1) 
    dict2 = deep_sort(dict2) 

    self.assertDictEqual(dict1, dict2) 

Cách tiếp cận này có những lợi ích của việc không quan tâm đến có bao nhiêu cấp độ sâu danh sách của bạn.

+2

'Ngoại lệ: '<' không được hỗ trợ giữa các trường hợp 'dict' và 'dict'' – tdc

1

Tôi gặp vấn đề tương tự, tôi phải kiểm tra xem các trường của mô hình có chính xác hay không. Và MyModel._meta.get_all_field_names() đôi khi trả về ['a', 'b'] và đôi khi ['b', 'a'].

Khi tôi chạy:

self.assertEqual(MyModel._meta.get_all_field_names(), ['a', 'b']) 

nó đôi khi thất bại.

Tôi giải quyết nó bằng cách đặt cả hai giá trị trong một set():

self.assertEqual(set(MyModel._meta.get_all_field_names()), set(['a', 'b'])) #true 

self.assertEqual(set(MyModel._meta.get_all_field_names()), set(['b', 'a'])) #true 

này sẽ không làm việc (trả về True) với:

self.assertEqual(set(['a','a','b','a']), set(['a','b'])) # Also true 

Nhưng kể từ khi tôi đang kiểm tra cho tên trường của một mô hình, và đó là duy nhất, điều này là tốt bởi tôi.

+0

Bạn có thể sử dụng ký pháp thiết lập để cải thiện điều này, thay vì' set ([' a ',' b ']) 'try' {' a ',' b '} '. Ngoài ra, có một hàm 'self.assertSetEqual ({'a', 'a', 'b', 'a'}, {'a', 'b'})' sẽ kiểm tra sự khác biệt giữa hai bộ và thất bại nếu chúng không chứa chính xác các yếu tố tương tự. – Mouscellaneous

Các vấn đề liên quan