72

Is there a 'decent' way in unittest to check the equality of the contents of two iterable objects? I am using a lot of tuples, lists and numpy arrays and I usually only want to test for the contents and not for the type. Currently I am simply casting the type:

self.assertEqual (tuple (self.numpy_data), tuple (self.reference_list))

I used this list comprehension a while ago:

[self.assertEqual (*x) for x in zip(self.numpy_data, self.reference_list)]

But this solution seems a bit inferior to the typecast because it only prints single values if it fails and also it does not fail for different lengths of reference and data (due to the zip-function).

Lucas Hoepner
  • 1,437
  • 1
  • 16
  • 21

3 Answers3

102

Python 3

Python >= 2.7

Community
  • 1
  • 1
Cédric Julien
  • 78,516
  • 15
  • 127
  • 132
  • This won't do what the OP requested, since it disregards the order of the items. – Sven Marnach Sep 19 '11 at 15:28
  • 1
    @Sven Marnach : right, I added the assertSequenceEqual that is not order-free – Cédric Julien Sep 19 '11 at 15:44
  • 2
    Slight clarification: 2.7 has the desired functionality, so I think you meant >=2.7 instead of >2.7. Also, those features are available in 2.4-2.6 via the [unittest2](http://pypi.python.org/pypi/unittest2) package. – Mu Mind Jan 22 '12 at 18:53
  • 5
    Also note that `assertSequenceEqual` cannot compare generators, as it seems try and call `len()` on the result. – Dan Passaro Jun 17 '13 at 19:20
  • 12
    I have tried using `assertSequenceEqual` to compare two `numpy` arrays. However, the test returns a value error saying that "(...) truth value of an array with more than one element is ambiguous." If `A = numpy.array([0, 1, 2, 3, 4, 5])` and `B = numpy.array([0, 1, 2, 3, 4, 5])`, running `self.assertSequenceEqual(A, B)` raises the error. But, if I use `self.assertSequenceEqual(list(A), list(B))` the test passes as expected. I just want to know if this the proper way of running the test? – regeirk Jul 02 '13 at 18:42
10

You can always add your own assertion methods to your TestCase class:

def assertSequenceEqual(self, it1, it2):
    self.assertEqual(tuple(it1), tuple(it2))

or take a look at how 2.7 defined it: http://hg.python.org/cpython/file/14cafb8d1480/Lib/unittest/case.py#l621

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • The definition in the linked code does something different than your implementation: It compares up to differences in the order of elements. – Sven Marnach Sep 19 '11 at 15:30
  • Oops: `assertItemsEqual` is unordered. I've fixed it to point to a more appropriate exemplar. – Ned Batchelder Sep 19 '11 at 15:43
  • also assertItemsEqual uses collections.Counter method, which uses the hash of the objects in the sequence. With sequences of User created objects without a specific hash implementation, assertItemsEqual will always fail (since the hash is based on object Id), even if the objects are equal (i.e. == is true). – Tony Suffolk 66 Aug 31 '14 at 21:59
0

It looks to me you care about the order of items in the sequences. Therefore, assertItemsEqual/assertCountEqual is not for you.

In Python 2.7 and in Python 3, what you want is self.assertSequenceEqual. This is sensitive to the order of the items.

user7610
  • 25,267
  • 15
  • 124
  • 150