我知道assertDictContainsSubset
可以在python 2.7中执行此操作,但由于某种原因,它在python 3.2中已弃用。那么有没有办法断言一个dict包含另一个没有assertDictContainsSubset
?
这似乎不太好:
for item in dic2:
self.assertIn(item, dic)
还有其他好方法吗?感谢
答案 0 :(得分:24)
>>> 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
限制:字典值必须是可清除的。
答案 1 :(得分:11)
虽然我正在使用pytest,但我在comment中找到了以下想法。它对我来说真的很棒,所以我觉得它在这里很有用:
assert dict1.items() <= dict2.items()
用于Python 3和
assert dict1.viewitems() <= dict2.viewitems()
for Python 2。
它适用于不可清洗的物品,但您无法准确知道哪个物品最终失败。
答案 2 :(得分:6)
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)
答案 3 :(得分:6)
接受的答案存在的一个大问题是,如果对象值中有不可散列的值,它就不起作用。第二件事是你没有得到有用的输出 - 测试通过或失败,但没有告诉你对象中的哪个字段是不同的。
因此,简单地创建子集字典然后测试它更容易。这样你就可以使用TestCase.assertDictEquals()
方法,它会在你的测试运行器中为你提供非常有用的格式化输出,显示实际和期望之间的差异。
我认为最令人愉快和pythonic的方法是使用简单的词典理解:
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)
答案 4 :(得分:1)
即使您在词典中有列表,这里的比较仍然有效:
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)
答案 5 :(得分:1)
这回答了一个比你要问的更广泛的问题,但我在我的测试工具中使用它来查看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
答案 6 :(得分:1)
您可以改为使用assertGreaterEqual()方法。
users = {'id': 28027, 'email': 'chungs.lama@gmail.com','created_at': '2005-02-13'}
data = {"email": "chungs.lama@gmail.com"}
self.assertGreaterEqual(user.items(), data.items())
答案 7 :(得分:0)
在Python 3和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和更低版本中,最好的选择是迭代第一个字典中的键,然后检查第二个字典中的键。
# Test if d1 is a subset of d2
all(k in d2 and d2[k] == d1[k] for k in d1)