assertDictContainsSubset
がpython 2.7でこれを行うことができることを知っていますが、何らかの理由でpython 3.2で廃止されています。 dictにはassertDictContainsSubset
のない別のものが含まれていますか?
これは良くないようです:
for item in dic2:
self.assertIn(item, dic)
他の良い方法は?ありがとう
>>> d1 = dict(a=1, b=2, c=3, d=4)
>>> d2 = dict(a=1, b=2)
>>> set(d2.items()).issubset( set(d1.items()) )
True
その他の方法:
>>> set(d1.items()).issubset( set(d2.items()) )
False
制限:辞書の値はハッシュ可能でなければなりません。
Pytestを使用していますが、 コメント で次のアイデアを見つけました。それは私にとって本当に素晴らしかったので、ここで役に立つと思いました:
assert dict1.items() <= dict2.items()
for Python 3および
assert dict1.viewitems() <= dict2.viewitems()
for Python 2。
ハッシュ不可のアイテムでも機能しますが、最終的にどのアイテムが失敗するかを正確に知ることはできません。
John1024のソリューションは私のために働いた。ただし、失敗した場合、どのキーが一致していないかを示すのではなく、False
のみを通知します。そこで、有用な失敗メッセージを出力する他のアサーションメソッドを使用して、非推奨のアサートメソッドを回避しようとしました。
expected = {}
response_keys = set(response.data.keys())
for key in input_dict.keys():
self.assertIn(key, response_keys)
expected[key] = response.data[key]
self.assertDictEqual(input_dict, expected)
受け入れられた答えの大きな問題は、オブジェクト値にハッシュできない値が含まれていると機能しないことです。 2つ目は、有用な出力が得られないことです。テストは成功または失敗しますが、オブジェクト内のどのフィールドが異なるかはわかりません。
そのため、サブセット辞書を作成してテストする方が簡単です。この方法では、TestCase.assertDictEquals()
メソッドを使用できます。これにより、テストランナーで実際の出力と期待される出力の差分を表示する非常に便利なフォーマット出力が得られます。
私がこれを行うための最も楽しいとPythonの方法は、そのような単純な辞書の理解を使用することだと思います:
_from unittest import TestCase
actual = {}
expected = {}
subset = {k:v for k, v in actual.items() if k in expected}
TestCase().assertDictEqual(subset, expected)
_
注:TestCaseを継承する子クラスに属するメソッドでテストを実行している場合(ほぼ確実にそうであるように)、それはただself.assertDictEqual(subset, expected)
です
これは、あなたが尋ねているよりも少し幅広い質問に答えますが、container
辞書にcontained
辞書のように見えるものが含まれているかどうかを確認するために、テストハーネスでこれを使用します。これにより、キーと値がチェックされます。さらに、キーワード'ANYTHING'
は、どのように一致するかを気にしないことを示します。
def contains(container, contained):
'''ensure that `contained` is present somewhere in `container`
EXAMPLES:
contains(
{'a': 3, 'b': 4},
{'a': 3}
) # True
contains(
{'a': [3, 4, 5]},
{'a': 3},
) # True
contains(
{'a': 4, 'b': {'a':3}},
{'a': 3}
) # True
contains(
{'a': 4, 'b': {'a':3, 'c': 5}},
{'a': 3, 'c': 5}
) # True
# if an `contained` has a list, then every item from that list must be present
# in the corresponding `container` list
contains(
{'a': [{'b':1}, {'b':2}, {'b':3}], 'c':4},
{'a': [{'b':1},{'b':2}], 'c':4},
) # True
# You can also use the string literal 'ANYTHING' to match anything
contains(
{'a': [{'b':3}]},
{'a': 'ANYTHING'},
) # True
# You can use 'ANYTHING' as a dict key and it indicates to match the corresponding value anywhere
# below the current point
contains(
{'a': [ {'x':1,'b1':{'b2':{'c':'SOMETHING'}}}]},
{'a': {'ANYTHING': 'SOMETHING', 'x':1}},
) # True
contains(
{'a': [ {'x':1, 'b':'SOMETHING'}]},
{'a': {'ANYTHING': 'SOMETHING', 'x':1}},
) # True
contains(
{'a': [ {'x':1,'b1':{'b2':{'c':'SOMETHING'}}}]},
{'a': {'ANYTHING': 'SOMETHING', 'x':1}},
) # True
'''
ANYTHING = 'ANYTHING'
if contained == ANYTHING:
return True
if container == contained:
return True
if isinstance(container, list):
if not isinstance(contained, list):
contained = [contained]
true_count = 0
for contained_item in contained:
for item in container:
if contains(item, contained_item):
true_count += 1
break
if true_count == len(contained):
return True
if isinstance(contained, dict) and isinstance(container, dict):
contained_keys = set(contained.keys())
if ANYTHING in contained_keys:
contained_keys.remove(ANYTHING)
if not contains(container, contained[ANYTHING]):
return False
container_keys = set(container.keys())
if len(contained_keys - container_keys) == 0:
# then all the contained keys are in this container ~ recursive check
if all(
contains(container[key], contained[key])
for key in contained_keys
):
return True
# well, we're here, so I guess we didn't find a match yet
if isinstance(container, dict):
for value in container.values():
if contains(value, contained):
return True
return False
辞書にリストがある場合でも機能する比較を次に示します。
superset = {'a': 1, 'b': 2}
subset = {'a': 1}
common = { key: superset[key] for key in set(superset.keys()).intersection(set(subset.keys())) }
self.assertEquals(common, subset)
代わりにassertGreaterEqual()メソッドを使用できます。
users = {'id': 28027, 'email': '[email protected]','created_at': '2005-02-13'}
data = {"email": "[email protected]"}
self.assertGreaterEqual(user.items(), data.items())
Python 3 and Python 2.7では、データをコピーせずに辞書のセットのような「アイテムビュー」を作成できます。これにより、比較を使用できます。サブセット関係をテストする演算子。
Python 3では、これは次のようになります。
_# Test if d1 is a sub-dict of d2
d1.items() <= d2.items()
# Get items in d1 not found in d2
difference = d1.items() - d2.items()
_
Python 2.7では、viewitems()
の代わりにitems()
メソッドを使用して同じ結果を得ることができます。
Python 2.6以前では、最初の辞書のキーを反復処理し、2番目の辞書に含まれているかどうかを確認するのが最善の策です。
_# Test if d1 is a subset of d2
all(k in d2 and d2[k] == d1[k] for k in d1)
_