Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Compare nested data structures in unittest

Tags:

python

Is there a way to compare nested data structures in unittest but ignoring concrete types of objects, like assertSequenceEqual but recursive, for example:

#!/usr/bin/env python

import unittest

class DeepCompareTestCase(unittest.TestCase):

    def test_compare(self):
        # this test fails
        self.assertSequenceEqual(
            [['abc', 'def']],
            (('abc', 'def'),)
        )

unittest.main()

(something like Test::Deep in Perl)

like image 661
el.pescado - нет войне Avatar asked Oct 19 '22 13:10

el.pescado - нет войне


1 Answers

Would something like this work?

import unittest
from itertools import zip_longest

class RecursiveTestCase(unittest.TestCase):
    def assertSequenceDeepEqual(self, x, y):
        MissingValue = MissingValueSentinel()
        for x, y, in zip_longest(x, y, fillvalue=MissingValue):
            try:
                self.assertSequenceDeepEqual(self, x, y)
            except TypeError:
                self.assertEqual(x, y)

                self.assertIsNot(x, MissingValue)
                self.assertIsNot(y, MissingValue)

class MissingValueSentinel(object):
    pass

zip_longest raises TypeError if one or more of the items is not an iterator, indicating you're at the bottom of the recursion.

If one of the iterators is shorter than the other, I have it returning a custom MissingValueSentinel object, which is detected by the assertIsNot calls at the end of the function. The only reason for this would be if x or y has a class that for whatever reason compares equal to even ad-hoc classes like MissingValueSentinel, but where assertEqual is still meaningful between two different objects of that class. That seems like a pretty weird edge case and you can probably safely ignore it.

Using zip_longest instead of zip prevents [1, 2, 3] incorrectly matching [1, 2].

like image 126
Paul Avatar answered Nov 03 '22 06:11

Paul