Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python unittest assertEqual failure when results are equal (Python v3.6)

So I was having an issue with unittest results failing due to the test claiming that an assertEqual statement was failing.

Error code:

AssertionError: {1: ((51, 98), (31, 4)), 2: ((51, 98), (49, 80)), 3: ((31, 4), (49, 80))} != {1: ((51, 98), (31, 4)), 2: ((51, 98), (49, 80)), 3: ((31, 4), (49, 80))}

Here's the unittest code below:

class InstanceTestCase(unittest.TestCase):

    def setUp(self):
        self.prob = Generate.populated_instance(3, 12345678)

        node_one = Node(51, 98)
        node_two = Node(31, 4)
        node_three = Node(49, 80)

        edge_one = Edge(node_one, node_two)
        edge_two = Edge(node_one, node_three)
        edge_three = Edge(node_two, node_three)

        self.comparison_edges = {1: edge_one, 2: edge_two, 3: edge_three}

    def test_Instance(self):
        self.assertEqual(self.prob.edges, self.compare_edges_dict)  # returning an error

which is testing these classes:

class Node:
    """Represents the nodes as points with a position x, y."""

    def __init__(self, x=0, y=0):
        """Create a new node at x, y."""
        self.x = x
        self.y = y

    def __str__(self):
        return "({0}, {1})".format(self.x, self.y)

    def __repr__(self):
        return str(self)

    def __eq__(self, other):
        if type(self) == type(other):
            return self.x == other.x and self.y == other.y
        else:
            raise TypeError

    def __hash__(self):
        return hash((self.x, self.y))


class Edge:
    """Represents the edges as having a length and being bounded by two points."""
    def __init__(self, node_one, node_two):
        """Create an edge using two nodes."""
        self.node_one = node_one
        self.node_two = node_two

    def __str__(self):
        return "({0}, {1})".format(self.node_one, self.node_two)

    def __repr__(self):
        return str(self)


class Instance:

    count = 0

    def __init__(self, node_count=0, seed=0, nodes=None, edges=None, solution_path=None, solve_time=0):
        """Create a new problem with x number of nodes.
        Leave seed blank for random seed, otherwise put an eight digit number to use for the seed."""
        self.node_count = node_count
        self.seed = seed
        self.nodes = nodes
        self.edges = edges
        self.solution_path = solution_path
        self.solve_time = solve_time
        Instance.count += 1

    # makes outputs from print easier to read
    def __str__(self):
        return "ID: {0}\n" \
               "Node count: {1}\n" \
               "Seed: {2}\n" \
               "Nodes: {3}\n" \
               "Edges: {4}\n" \
               "Solve time: {5}".format(self.problem_id,
                                        self.node_count,
                                        self.seed,
                                        self.nodes,
                                        self.edges,
                                        self.solve_time)

    def __repr__(self):
        return str(self)

The prob object being created in the testing code is an instance of the Instance class, which, among other things, contains two dictionaries (after a method call), one for the nodes and one for the edges. The nodes are generated using the populated_instance method of the Generate class, and the edges are generated from the nodes by different method call within the populated_instance method.

The prob.edges dictionary looks like this:

{1: ((51, 98), (31, 4)), 2: ((51, 98), (49, 80)), 3: ((31, 4), (49, 80))}

and is made up of instances of the Node class contained within instances of the Edge class. As you can see in the unittest code above, I've created an equivalent dictionary using the same objects with the same values.

So, I knew for sure that the prob.edges dictionary and the comparison_edges dictionary were identical, were entirely made up of properly instantiated class objects, and that I wasn't comparing any of these objects to strings that looked like objects.

I found this SO question about a similar problem: Python unittest failure when results appear equal... however it shed no light on my issue.

After an hour or so I eventually realised what was happening, and it was a different problem entirely. So I'm going to post my question and the answer as well.

like image 540
LangerNZ Avatar asked Jul 31 '26 13:07

LangerNZ


1 Answers

Without an own __eq__() method Python compares just the IDs of your objects and they are of course not equal. If you want to test equality of the attributes of different objects you need the __eq__() method. In fact you could compare in this method whatever you want. I had an example where equality was defined as equality of two out of five attributes. The remaining three attributes were not considered.

By the way: in your __eq__() method you should check the equality of the types of your objects as well. Imagine two instances of different classes which have at random the same attributes ...

like image 106
Humbalan Avatar answered Aug 03 '26 04:08

Humbalan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!