结果相等时,Python单元测试assertEqual失败(Python v3.6)

时间:2018-08-17 15:01:11

标签: python python-unittest

由于测试声称unittest语句失败,因此我遇到assertEqual结果失败的问题。

错误代码:

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))}

这是下面的单元测试代码:

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

正在测试这些类:

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)

在测试代码中创建的prob对象是Instance类的实例,其中除其他外,包含两个字典(在方法调用之后),一个字典用于节点,一个字典用于节点。对于边缘。使用populated_instance类的Generate方法生成节点,并通过populated_instance方法内的不同方法调用从节点生成边缘。

prob.edges词典如下:

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

并且由Node类的实例中包含的Edge类的实例组成。如您在上面的单元测试代码中所看到的,我已经使用具有相同值的相同对象创建了一个等效字典。

因此,我确定prob.edges字典和comparison_edges字典是相同的,完全由正确实例化的类对象组成,并且我没有将这些对象与看起来像对象的字符串。

我找到了一个类似问题的SO问题: Python unittest failure when results appear equal ...但是对我的问题没有任何启示。

一个小时后,我终于意识到发生了什么,这完全是另一个问题。所以我也要发布我的问题和答案。

2 个答案:

答案 0 :(得分:2)

没有自己的__eq__()方法,Python仅比较对象的ID,它们当然是不相等的。如果要测试不同对象的属性是否相等,则需要__eq__()方法。实际上,您可以使用此方法进行比较。我有一个示例,其中平等定义为五个属性中的两个相等。未考虑其余三个属性。

顺便说一句:在您的__eq__()方法中,您还应该检查对象类型的相等性。想象一下不同类别的两个实例,它们随机具有相同的属性...

答案 1 :(得分:1)

对于我来说,答案是我没有在__eq__()类中实现Edge方法。

此方法将由其他一些方法自动调用,如果您的类中未实现该方法,则需要进行相等性检查的方法可能无法正常工作。

我的Edge类最初看起来像这样:

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)

并包括此内容之后...

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

assertEqual中使用的相等性检查效果很好。

(注意:我已经在我的__eq__()类中实现了覆盖的Node方法,并且测试确认删除该方法也破坏了上面的检查。)

从python文档(https://docs.python.org/2/library/unittest.html)看这件事:

  

assertEqual(first, second, msg=None)测试第一个和第二个是   等于。如果值不相等,则测试将失败。

     

此外,如果first和second是完全相同的类型,并且   列表,元组,字典,集合,frozenset或unicode或   子类向addTypeEqualityFunc()注册特定类型   相等函数将被调用以生成更有用的   默认错误消息(另请参见类型特定方法的列表)。

     

在2.7版中进行了更改:添加了针对特定类型的自动调用   相等函数。

在我看来,自定义类上正在调用“特定于类型的相等函数”,因此,如果自定义__eq__()方法不存在,则检查将失败。

有关更多详细信息,请参见下面@Humbalan的回答:)