如何通过将assertSequenceEqual应用于值来实现assertDictEqual

sap*_*api 18 python unit-testing python-unittest

我知道,在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 ><
Run Code Online (Sandbox Code Playgroud)

我如何通过递归地将类似语义应用于值来测试诸如d1d2正确比较它们的相等的字典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)
Run Code Online (Sandbox Code Playgroud)

上面代码的问题是错误消息不如内置断言那么好,并且可能存在我忽略的边缘情况(因为我刚刚写了这篇文章).

Chr*_*lla 8

而不是重写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
Run Code Online (Sandbox Code Playgroud)

然后排序,并使用正常的assertDictEqual:

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

    self.assertDictEqual(dict1, dict2)
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是不关心列表的深度.

  • `例外:'dict'和'dict'的实例之间不支持'<' (2认同)

mar*_*eau 5

TestCase.assertEqual()方法调用类' assertDictEqual()for 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()
Run Code Online (Sandbox Code Playgroud)

输出:

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()
Run Code Online (Sandbox Code Playgroud)