Подтвердить что ты не робот

Как достичь assertDictEqual с помощью assertSequenceEqual, применяемого к значениям

Я знаю, что при выполнении assertEqual в словаре вызывается assertDictEqual. Аналогично, assertEqual в последовательности будет выполнять assertSequenceEqual.

Однако, когда assertDictEqual сравнивает значения, кажется, что он не использует assertEqual, и поэтому assertSequenceEqual не вызывается.

Рассмотрим следующие простые словари:

lst1 = [1, 2]
lst2 = [2, 1]

d1 = {'key': lst1}
d2 = {'key': lst2}

self.assertEqual(lst1, lst2) # True
self.assertEqual(d1, d2) # False ><

Как я могу тестировать словари, такие как d1 и d2, чтобы их соответствие правильно сравнивалось, рекурсивно применяя семантику assertEqual к значениям?

Я хочу избежать использования внешних модулей (как предложено в этом вопросе), если это вообще возможно, если только они не являются родными расширениями django.


ИЗМЕНИТЬ

По существу, для меня это встроенная версия:

def assertDictEqualUnorderedValues(self, d1, d2):
    for k,v1 in d1.iteritems():
        if k not in d2:
            self.fail('Key %s missing in %s'%(k, d2))

        v2 = d2[k]

        if isinstance(v1, Collections.iterable) and not isinstance(v1, basestring):
            self.assertValuesEqual(v1, v2)
        else:
            self.assertEqual(v1, v2)

Проблема с вышеприведенным кодом заключается в том, что сообщения об ошибках не так хороши, как утверждается встроенным, и, возможно, в некоторых случаях я игнорировал (как я только что написал это с моей головы).

4b9b3361

Ответ 1

Вместо того, чтобы переопределять assertDictEqual, почему бы вам не рекурсивно не отсортировать свои dicts?

def deep_sort(obj):
    """
    Recursively sort list or dict nested lists
    """

    if isinstance(obj, dict):
        _sorted = {}
        for key in sorted(obj):
            _sorted[key] = deep_sort(obj[key])

    elif isinstance(obj, list):
        new_list = []
        for val in obj:
            new_list.append(deep_sort(val))
        _sorted = sorted(new_list)

    else:
        _sorted = obj

    return _sorted

Затем сортируйте и используйте обычный assertDictEqual:

    dict1 = deep_sort(dict1)
    dict2 = deep_sort(dict2)

    self.assertDictEqual(dict1, dict2)

Этот подход имеет преимущество: не заботиться о том, сколько уровней в ваших списках.

Ответ 2

Метод TestCase.assertEqual() вызывает класс assertDictEqual() для dicts, поэтому просто переопределяем его в вашем подклассе. Если вы используете только другие методы assertXXX в методе, сообщения об ошибках должны быть почти такими же хорошими, как и встроенные утверждения, но если вы не можете предоставить аргумент ключевого слова msg, когда вы вызываете их для управления отображаемым.

import collections
import unittest

class TestSOquestion(unittest.TestCase):

    def setUp(self):
        pass # whatever...

    def assertDictEqual(self, d1, d2, msg=None): # assertEqual uses for dicts
        for k,v1 in d1.iteritems():
            self.assertIn(k, d2, msg)
            v2 = d2[k]
            if(isinstance(v1, collections.Iterable) and
               not isinstance(v1, basestring)):
                self.assertItemsEqual(v1, v2, msg)
            else:
                self.assertEqual(v1, v2, msg)
        return True

    def test_stuff(self):
        lst1 = [1, 2]
        lst2 = [2, 1]

        d1 = {'key': lst1}
        d2 = {'key': lst2}

        self.assertItemsEqual(lst1, lst2) # True
        self.assertEqual(d1, d2) # True

if __name__ == '__main__':
    unittest.main()

Вывод:

> python unittest_test.py
.
---------------------------------------------------------------------->
Ran 1 test in 0.000s

OK

>

Ответ 3

У меня была та же проблема, я должен был проверить, правильно ли поля модели. И MyModel._meta.get_all_field_names() иногда возвращает ['a', 'b'], а иногда ['b', 'a'].

Когда я запустил:

self.assertEqual(MyModel._meta.get_all_field_names(), ['a', 'b'])

он иногда терпит неудачу.

Я решил это, поставив оба значения в set():

self.assertEqual(set(MyModel._meta.get_all_field_names()), set(['a', 'b'])) #true

self.assertEqual(set(MyModel._meta.get_all_field_names()), set(['b', 'a'])) #true

Это не сработает (возвращает True) с помощью:

self.assertEqual(set(['a','a','b','a']), set(['a','b']))  # Also true 

Но так как я проверяю имена полей модели, и они уникальны, это хорошо для меня.