9

I'm learning how to use Pytest (and unit testing in general) and I would like to write a test to check if two objects of the same class have identical attributes.

Example:

class Something(object):
    def __init__(self, a, b):
        self.a, self.b = a, b

    def __repr__(self):
        return 'Something(a={}, b={})'.format(self.a, self.b)

def test_equality():
    obj1 = Something(1, 2)
    obj2 = Something(1, 2)
    assert obj1.a == obj2.a
    assert obj1 == obj2

This test fails with AssertionError on third assert:

    def test_equality():
        obj1 = Something(1, 2)
        obj2 = Something(1, 2)
        assert obj1.a == obj2.a
        assert obj1.b == obj2.b                                                                                                                                                                                                               
>       assert obj1 == obj2                                                                                                                                                                                                                   
E       assert Something(a=1, b=2) == Something(a=1, b=2)                                                                                                                                                                                     

tests/test_model.py:13: AssertionError

It is possible in Python or Pytest to use just assert obj1 == obj2? Should I implement "rich comparison" methods for each class I would like to test that way or there is some simpler way?

maln0ir
  • 521
  • 2
  • 5
  • 13
  • 1
    Usually it is better to implement a comparison operator, like `__eq__`, since some objects can be equal, even if the fields are not. An *ugly* hack that usually works if (a) the attributes themselves are comparable, and (b) all attributes are stored in the dict work is `type(obj1) == type(obj2) and obj1.__dict__ == obj2.__dict__`, but this is very limited. – Willem Van Onsem Feb 12 '18 at 19:23
  • @Idos: Yes, it looks very similar – maln0ir Feb 12 '18 at 19:27

1 Answers1

13

Override the __eq__ function of Something.

def __eq__(self, other)
    if isinstance(self, other.__class__):
        return self.a == other.a and self.b == other.b
    return False

Also.

assert obj1 == obj2

is actually a two-part statement. first is the expression obj1 == obj2, which calls obj1.__eq__(obj2) and returns a boolean, the second asserts that boolean for truth.

TTT
  • 1,952
  • 18
  • 33
  • 1
    Overriding the __eq__ operator could have unintended consequences here, depending on how the uniqueness of this object is determined. – Michael Robellard Feb 12 '18 at 19:27
  • @MichaelRobellard How? If reference equality is expected, the __is__ operator should be used. It is clear the OP wishes to define two objects of Something as equal if their fields are equivalent. – TTT Feb 12 '18 at 19:29
  • if you override the __eq__ you should know the uniqueness should be. For me this is the correct answer. – Tzomas Feb 12 '18 at 19:29
  • I need to override just __eq__? I thought I need to implement all six methods, but just one it seems to work. Thanks! – maln0ir Feb 12 '18 at 19:32
  • An example of where this would be bad is if you subclass your class, do you want a subclass with both those properties set to be equal to the base class? Sometimes you would want to and sometimes not. depends on the circumstances. – Michael Robellard Feb 12 '18 at 19:48
  • In that case, the equals operator should be overrided in the subclass as well with any additional fields or equivalence parameters necessary for the subclass and a call to the superclass eq, that's an architecture problem, I don't think its a problem intrinsically with overriding \__eq__ – TTT Feb 12 '18 at 19:50
  • There isn't a problem with overriding __eq__ necessarily. I just think it could easily bite someone that doesn't realize all the ramifications. – Michael Robellard Feb 12 '18 at 19:53
  • 1
    Indeed, as are all decisions to override any method and combine with inheritance in oo languages. – TTT Feb 12 '18 at 19:54