web-dev-qa-db-de.com

Wie kann man behaupten, dass ein Diktat ein anderes Diktat ohne assertDictContainsSubset in Python enthält?

Ich weiß, dass assertDictContainsSubset dies in Python 2.7 tun kann, aber aus irgendeinem Grund ist es in Python 3.2 veraltet. Gibt es eine Möglichkeit, zu behaupten, dass ein Diktier ein anderes ohne assertDictContainsSubset enthält?

Das scheint nicht gut zu sein:

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

irgendein anderer guter Weg? Vielen Dank

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

Und andersherum:

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

Einschränkung: Die Wörterbuchwerte müssen hashbar sein.

22
John1024

Obwohl ich pytest verwende, fand ich die folgende Idee in einem Kommentar . Es hat wirklich toll für mich funktioniert, also dachte ich, es könnte hier nützlich sein:

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

für Python 3 und

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

für Python 2.

Es funktioniert mit nicht-hashbaren Elementen, aber Sie können nicht genau wissen, welches Element letztendlich fehlschlägt.

10
kepler

Die Lösung von John1024 hat für mich funktioniert. Im Fehlerfall wird jedoch nur False angezeigt, anstatt Ihnen zu zeigen, welche Schlüssel nicht übereinstimmen. Also habe ich versucht, die veraltete Assert-Methode zu vermeiden, indem ich andere Assertions-Methoden verwendete, die hilfreiche Fehlermeldungen ausgeben:

    expected = {}
    for key in input_dict.keys():
        self.assertIn(key, set(response.data.keys()))
        expected[key] = response.data[key]
    self.assertDictEqual(input_dict, expected)
6
Risadinha

Das große Problem mit der akzeptierten Antwort ist, dass sie nicht funktioniert, wenn Sie nicht hashierbare Werte in den Objektwerten haben. Die zweite Sache ist, dass Sie keine nützliche Ausgabe erhalten - der Test besteht oder schlägt fehl, sagt jedoch nicht, welches Feld innerhalb des Objekts anders ist.

Daher ist es einfacher, ein Teilmengenwörterbuch zu erstellen und es dann zu testen. Auf diese Weise können Sie die TestCase.assertDictEquals()-Methode verwenden, mit der Sie in Ihrem Testläufer eine sehr nützliche formatierte Ausgabe erhalten, die den Unterschied zwischen dem tatsächlichen und dem erwarteten Wert angibt.

Ich denke, der angenehmste und pythonic-Weg, dies zu tun, ist ein einfaches Wörterbuchverständnis als solches:

from unittest import TestCase


actual = {}
expected = {}

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

HINWEIS Wenn Sie Ihren Test in einer Methode ausführen, die zu einer untergeordneten Klasse gehört, die von TestCase geerbt wird (wie Sie es fast sicher sein sollten), ist dies nur self.assertDictEqual(subset, expected)

6
Sam Redway

Dies beantwortet eine etwas breitere Frage als Sie sich die Frage stellen, aber ich verwende dies in meinen Testausrüstungen, um festzustellen, ob das container-Wörterbuch etwas enthält, das wie das contained-Wörterbuch aussieht. Dies überprüft Schlüssel und Werte. Zusätzlich können Sie das Schlüsselwort 'ANYTHING' verwenden, um anzugeben, dass es Ihnen egal ist, wie es passt.

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
1
JnBrymn

Hier ist ein Vergleich, der auch dann funktioniert, wenn Sie Listen in den Wörterbüchern haben:

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)
1
user1338062

Sie können stattdessen die assertGreaterEqual () -Methode verwenden.

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

data = {"email": "[email protected]"}

self.assertGreaterEqual(user.items(), data.items())
0
Bomjon Bedu

In Python 3 und Python 2.7 können Sie eine satzähnliche "Elementansicht" eines Diktats erstellen, ohne Daten zu kopieren. Auf diese Weise können Sie Vergleichsoperatoren verwenden, um eine Teilmengenbeziehung zu testen.

In Python 3 sieht das so aus:

# 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 können Sie die viewitems()-Methode anstelle von items() verwenden, um dasselbe Ergebnis zu erzielen.

In Python 2.6 und darunter ist es am besten, wenn Sie die Tasten im ersten Diktat durchlaufen und prüfen, ob sie in den zweiten aufgenommen werden.

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