2013-01-23 34 views
9

在爲我的課寫一些測試時,我遇到了一個有趣的簡單問題。我想斷言包含一些列表的DictEqual兩個字典。但是這名單可以不在同一方式進行分類 - >導致測試失敗Python單元測試 - 用列表聲明字典

例子:

def test_myobject_export_into_dictionary(self): 
    obj = MyObject() 
    resulting_dictionary = { 
      'state': 2347, 
      'neighbours': [1,2,3] 
     } 
    self.assertDictEqual(resulting_dictionary, obj.exportToDict()) 

這無法從時間到時間,具體取決於要素的順序列表

FAIL: test_myobject_export_into_dictionary 
------------------------------------ 
- 'neighbours': [1,2,3], 
+ 'neighbours': [1,3,2], 

任何想法如何以簡單的方式來斷言?

我正在考慮在比較之前使用set而不是list或排序列表。

+0

如果你有這個問題的很多實例,我建議查看[@Jon Reid](http://stackoverflow.com/a/14493005/881224)的答案。 – Droogans

回答

7

你可以嘗試PyHamcrest(例校正)

assert_that(obj.exportToDict(), has_entries(
            { 'state': 2347, 
             'neighbours': contains_inanyorder(1,2,3) })) 

(前值2347實際上是被包裹在一個隱含的equal_to匹配。)

+0

起初我就像是「一個鬆散收集匹配的圖書館?」...然後我意識到它似乎有幾個用途。尼斯鏈接。 – Droogans

+0

這看起來很酷。我喜歡那句風格化的測試斷言。我一定會使用這個框架進行測試。但是,就我而言,使用集合而不是列表可能更簡單。如果我用幾個列表來斷言更大的字典,那麼對於一個斷言來說,它開始成爲大量的寫作。 –

+0

@sjudǝʊ然後我可能會改變測試,使用'has_entry'而不是'has_entries'並單獨測試每個條目。 –

0

如何使用all

assert all((k,v) in resulting_dictionary.iteritems() 
      for (k,v) in obj.exportToDict().iteritems()) 

我用這樣的事情與py.test,但我認爲它應該爲你工作。


一位評論者指出,這個命令會讓我在這裏 - 足夠公平......我只是使用集合,然後。

+0

這不起作用,''('neighbors',[1,2,3])''不在'[('neighbors',[1,3,2]),...]'' ! – mouad

+0

啊,好的。那麼他可以使用套。 – BenDundee

+0

確實。集合可能是最直接的解決方案 –

0

你可以這樣做:

a = {i:sorted(j) if isinstance(j, list) else j for i,j in resulting_dictionary.iteritems()} 
b = {i:sorted(j) if isinstance(j, list) else j for i,j in obj.exportToDict().iteritems()} 
self.assertDictEqual(a, b) 
+0

當然,假定所有值都可以並應該排序。第一個在OP的小例子中並不是真的,後者是預期的恕我直言 - 列表順序並不重要。 – delnan

+0

我以爲他的意思是價值永遠是名單。 – thikonom

+0

關鍵'neighbours'的值,是的。但是你的代碼也會嘗試對所有其他值進行排序(在OP的例子中,鍵值「state」是一個整數)。 – delnan

0

也許你可以分別檢查兩個元素:

obj_dict = obj.exportToDict() 
    self.assertEqual(resulting_dictionary['state'], obj_dict['state']) 
    self.assertCountEqual(resulting_dictionary['neighbours'], obj_dict['neighbours'])