python 如何Assert一个dict包含另一个dict而不用assertDictContainsSubset?[duplicate]

mbjcgjjk  于 2023-01-12  发布在  Python
关注(0)|答案(8)|浏览(158)
    • 此问题在此处已有答案**:

Python unittest's assertDictContainsSubset recommended alternative [duplicate](4个答案)
1年前关闭。
我知道assertDictContainsSubset在python 2.7中可以做到这一点,但由于某些原因,它在python 3.2中被弃用了。那么,有没有办法Assert一个dict包含另一个没有assertDictContainsSubset的dict呢?
这似乎不太好:

for item in dic2:
    self.assertIn(item, dic)

还有别的好办法吗?谢谢

krcsximq

krcsximq1#

虽然我使用的是pytest,但我在一条评论中发现了下面的想法,它对我来说非常有用,所以我认为它在这里可能会很有用。
巨蟒3:

assert dict1.items() <= dict2.items()

巨蟒2:

assert dict1.viewitems() <= dict2.viewitems()

它适用于不可散列的项,但您无法确切地知道哪个项最终会失败。

zf9nrax1

zf9nrax12#

>>> 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
  • 限制:* 字典值必须是可散列的。
hc2pp10m

hc2pp10m3#

可接受答案的一个大问题是,如果对象值中有不可散列的值,它就不起作用;第二个问题是,你得不到有用的输出--测试通过或失败,但没有告诉你对象中的哪个字段不同。
因此,简单地创建一个子集字典,然后测试它会更容易。这样,您可以使用TestCase.assertDictEquals()方法,它将在您的测试运行程序中提供非常有用的格式化输出,显示实际与预期之间的差异。
我认为最令人愉快和深奥的方法是用一个简单的字典来理解:

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)

yizd12fk

yizd12fk4#

John1024的解决方案对我很有效,但是,如果失败了,它只会告诉你False,而不会告诉你哪些键不匹配,所以,我尝试使用其他Assert方法来避免使用已弃用的assert方法,这些方法会输出有用的失败消息:

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

m528fe3b5#

您可以使用assertGreaterEqualassertLessEqual

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())
self.assertLessEqual(data.items(), user.items())  # Reversed alternative

请务必指定.items(),否则它将不起作用。

9nvpjoqh

9nvpjoqh6#

在Python 3和Python 2.7中,你可以创建一个dict的类似于集合的“项视图”,而不需要复制任何数据,这允许你使用比较操作符来测试子集关系。
在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及以下版本中,最好的办法是迭代第一个dict中的键,并检查第二个dict中的包含。

# Test if d1 is a subset of d2
all(k in d2 and d2[k] == d1[k] for k in d1)
esbemjvw

esbemjvw7#

这回答了一个比你要问的更广泛的问题,但是我在我的测试工具中使用它来检查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
bvpmtnay

bvpmtnay8#

下面是一个比较,即使你的字典中有列表也可以:

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)

相关问题