I know assertDictContainsSubset can do this in python 2.7, but for some reason it’s deprecated in python 3.2. So is there any way to assert a dict contains another one without assertDictContainsSubset?

This seems not good:

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

any other good way? Thanks

Although I’m using pytest, I found the following idea in a comment. It worked really great for me, so I thought it could be useful here:

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

for Python 3 and

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

for Python 2.

It works with non-hashable items, but you can’t know exactly which item eventually fails.

>>> d1 = dict(a=1, b=2, c=3, d=4)
>>> d2 = dict(a=1, b=2)
>>> set(d2.items()).issubset( set(d1.items()) )
True

And the other way around:

>>> set(d1.items()).issubset( set(d2.items()) )
False

Limitation: the dictionary values have to be hashable.

The big problem with the accepted answer is that it does not work if you have non hashable values in your objects values. The second thing is that you get no useful output – the test passes or fails but doesn’t tell you which field within the object is different.

As such it is easier to simply create a subset dictionary then test that. This way you can use the TestCase.assertDictEquals() method which will give you very useful formatted output in your test runner showing the diff between the actual and the expected.

I think the most pleasing and pythonic way to do this is with a simple dictionary comprehension as such:

from unittest import TestCase


actual = {}
expected = {}

subset = {k:v for k, v in actual.items() if k in expected}
TestCase().assertDictEqual(subset, expected)

NOTE obviously if you are running your test in a method that belongs to a child class that inherits from TestCase (as you almost certainly should be) then it is just self.assertDictEqual(subset, expected)

John1024’s solution worked for me. However, in case of a failure it only tells you False instead of showing you which keys are not matching. So, I tried to avoid the deprecated assert method by using other assertion methods that will output helpful failure messages:

    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)

You can use assertGreaterEqual or assertLessEqual.

users = {'id': 28027, 'email': '[email protected]', 'created_at': '2005-02-13'}
data = {"email": "[email protected]"}

self.assertGreaterEqual(user.items(), data.items())
self.assertLessEqual(data.items(), user.items())  # Reversed alternative

Be sure to specify .items() or it won’t work.

In Python 3 and Python 2.7, you can create a set-like “item view” of a dict without copying any data. This allows you can use comparison operators to test for a subset relationship.

In Python 3, this looks like:

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

In Python 2.7 you can use the viewitems() method in place of items() to achieve the same result.

In Python 2.6 and below, your best bet is to iterate over the keys in the first dict and check for inclusion in the second.

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

This answers a little broader question than you’re asking but I use this in my test harnesses to see if the container dictionary contains something that looks like the contained dictionary. This checks keys and values. Additionally you can use the keyword 'ANYTHING' to indicate that you don’t care how it matches.

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

Here is a comparison that works even if you have lists in the dictionaries:

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)