20

私はassertEqual、辞書で実行するときにassertDictEqual呼び出されることを知っています。同様にassertEqual、シーケンスでは が実行されますassertSequenceEqual

ただし、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 ><

のようなセマンティクスを値に再帰的に適用することにより、等値が適切に比較されるなどのd1辞書をテストするにはどうすればよいですか?d2assertEqual

ネイティブの django 拡張機能でない限り、可能であれば外部モジュール (この質問で提案されているように) の使用を避けたいと考えています。


編集

基本的に、私が求めているのは、これの組み込みバージョンです。

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)

上記のコードの問題は、エラー メッセージが組み込みのアサートほど適切ではないことです。おそらく、無視したエッジ ケースが存在する可能性があります (頭のてっぺんから書いたように)。

4

3 に答える 3

8

assertDictEqual をオーバーライドするのではなく、最初に辞書を再帰的にソートしてみませんか?

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)

このアプローチには、リストのレベル数を気にしないという利点があります。

于 2015-01-14T18:03:37.127 に答える
1

私は同じ問題を抱えていました。モデルのフィールドが正しいかどうかをテストする必要がありました。MyModel._meta.get_all_field_names() は ['a','b'] を返すこともあれば、['b','a'] を返すこともあります。

私が実行すると:

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

時々失敗します。

両方の値を 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

これは次の場合には機能しません (True を返します)。

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

しかし、私はモデルのフィールド名をチェックしていて、それらは一意であるため、これは私にとって良いことです.

于 2015-08-17T12:18:51.637 に答える