lmiguelvargasf lmiguelvargasf - 4 days ago 7
Python Question

Unsupported operand(s) types(s) when trying to assertAlmostEqual/assertEqual

I am trying to test that two objects are equal. The type of this objects is Point which is a class defined by ROS (Robot Operating System). I have the following test:

def test_when_getting_position_after_2s_then_position_at_2s_is_returned(self):
self.expected_position.x = -self.radius
self.expected_position.y = 0
self.assertAlmostEqual(
self.expected_position,
self.trajectory.get_position_at(2))


I am using
unittest
, and when I try to assert if they are almost equal, I am getting an error which says:


TypeError: unsupported operand type(s) for -: 'Point' and 'Point'


I get the same error when I use
assertEqual
, and I know I can do this:

self.assertAlmostEqual(self.expected_position.x, self.trajectory.get_position_at(1).x)
self.assertAlmostEqual(self.expected_position.y, self.trajectory.get_position_at(1).y)


However, I would like to be able to assert position and not specific fields. How can I achieve this?

Edit: The full traceback of the exception is:

Error
Traceback (most recent call last):
File "/usr/lib/python2.7/unittest/case.py", line 329, in run
testMethod()
File "/home/m/turtlebot_ws/src/trajectory_tracking/src/test/trajectory/test_astroid_trajectory.py", line 26, in test_when_getting_position_after_1s_then_position_at_1s_is_returned
self.assertAlmostEqual(self.expected_position, self.trajectory.get_position_at(1))
File "/usr/lib/python2.7/unittest/case.py", line 554, in assertAlmostEqual
if round(abs(second-first), places) == 0:
TypeError: unsupported operand type(s) for -: 'Point' and 'Point'

Answer

assertAlmostEqual(a, b) requires abs(a - b) to be valid, but you did not define the subtraction operator for the Point type, thus the error.

class Point(object):
    ...
    def __sub__(self, other):   # <-- define the subtraction operator so `a - b` is valid
        return Vector(self.x - other.x, self.y - other.y)

class Vector(object):
    ...
    def __abs__(self):    # <-- define the absolute function so `abs(v)` is valid
        return (self.x*self.x + self.y*self.y)**0.5

If you cannot provide __sub__ in the class definition, you could use monkey-patching to provide it in your test case.

def sub_point(self, other):
    return complex(self.x - other.x, self.y - other.y)
    # ^ for simplicity we abuse a complex number as a 2D vector.

Point.__sub__ = sub_point
Comments