2013-08-27 1 views
17

辞書にassertEqualを実行すると、assertDictEqualが呼び出されます。同様に、配列上のassertEqualassertSequenceEqualを実行します。assertDictEqualを達成する方法値に適用される

ただし、assertDictEqualが値を比較している場合は、assertEqualが使用されていないように見えるため、assertSequenceEqualは呼び出されません。

は、次の簡単な辞書を考えてみましょう:

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

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

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

にはどうすれば再帰的な値にassertEqual様セマンティクスを適用することにより、このようd1とその平等が正しく比較されるようにd2などの辞書をテストすることができますか?

ネイティブのdjango拡張でない限り、可能であれば外部モジュール(推奨のin this question)を使用しないでください。


基本的に、私は後にしていますが、このバージョンで構築されたEDIT

:上記のコードの問題は、エラーメッセージがほど良くないということである

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) 

(私が頭の上から書いたように)私は無視してしまったかもしれない事例があります。

+2

'unittest'モジュールで、' self.assertEqual(lst1、lst2) 'はTrueではありません - >' AssertionError:リストは異なります:[1、2]!= [2、1] '。 – martineau

+0

@martineau - 私の間違い;私はドキュメントのその部分を誤解しました。 assertSequenceEqualではなくassertItemsEqualを探しています – sapi

+1

'lst1'と' lst2'を同じようにして最初の 'assertEqual'が成功すれば、2番目も成功します。 – martineau

答えて

4

TestCase.assertEqual()メソッドは、dictsのクラス 'assertDictEqual()を呼び出すので、サブクラスの導出でオーバーライドするだけです。メソッド内に他のassertXXXメソッドしか使用しない場合、エラーメッセージはビルトインアサートとほぼ同じくらい良いはずですが、表示されているものを制御するために呼び出すときにmsgキーワード引数を指定できます。

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

出力:

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

OK 

> 
+1

私はリストの順序を保証することはできません。テストはdjangoフレームワークのためのものであり、テストセットと期待される結果との間で同じデータベース照会の順序に依存することはできません。私が気にするのは、APIが私に*正しい*値を与えるということです。 – sapi

+0

OK、しかし、私はまだあなたのコードで最初の 'assertEqual(lst1、lst2)'がなぜ/どのように期待されるのか理解していません。 – martineau

+0

このソリューションは、深くネストされたdicts +リストでは機能しません。ソートに基づいた解決策があります。 – Federico

7

よりもむしろassertDictEqualをオーバーライドし、なぜあなたは再帰的に最初にあなたのdictsを並べ替えるませんか?

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 

はその後、ソート、および通常のassertDictEqualを使用します。

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

    self.assertDictEqual(dict1, dict2) 

このアプローチは、あなたのリストはどのように多くのレベルの深気にしないという利点があります。

+2

'例外:' <'は' dict 'と' dict 'のインスタンス間ではサポートされていません – tdc

1

私は同じ問題を抱えていました。モデルのフィールドが正しいかどうかをテストしなければなりませんでした。 MyModel._meta.get_all_field_names()は時々['a'、 'b']を返します。時には['b'、 'a']も返します。

私が実行します。

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

それが時々失敗します。

私は)(セット内の両方の値を置くことによってそれを解決:

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 

これは、と(真を返す)は動作しません。

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

しかし、私は、フィールド名をチェックしていますので、モデルの、そしてそれらは独特です、これは私によって良いです。

+0

'set([' a '、' b '])ではな​​く、 a '、' b '} 'とする。また、 '' self.assertSetEqual({'a'、 'a'、 'b'、 'a'}、{'a'、b '}) 'という関数があります。それらが全く同じ要素を含んでいなければ失敗する。 – Mouscellaneous

関連する問題