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.
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 ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With