如何在Python的unittest模块中使用assert比较两个对象列表?

4

我有一个方法,它返回一个特定类别(我们称之为类A)的对象列表,该类别具有属性a、b和c,以及方法my_method。因此,我得到了以下内容:

my_method() -> [A(a1, b1, c1), A(a2, b2, c2), A(a3, b3, c3)]

我希望对这个方法进行单元测试,但我不太清楚应该使用哪种断言方法来完成测试。

我想写出类似下面的代码:

self.assertListEqual(my_method(), [A(a1, b1, c1), A(a2, b2, c2), A(a3, b3, c3)])

注意,这行代码不起作用(测试失败),因为我认为它无法处理对象列表(仅适用于基本类型列表,如数字列表)。我收到了以下错误信息:

First differing element 0

这里有一个细节,展示了那些第一批对象有不同的地址(当然是正常的),但这不是我想要比较的。我只想比较属性是否相等(FYI,属性a,b和c是“基本”类型,即字符串或数字)。

元素的顺序不重要。所以我只想在两个列表都包含实际不同的元素时(而不是以不同的顺序相同)才会失败。我正在使用Python3。

谢谢!


1
如果元素的顺序不重要,比较set而不是list;此外,您没有说明A是否实现了__eq__(它需要__hash____eq__用于在字典和集合中使用)。 - jonrsharpe
好的,假设我已经实现了__eq____hash__方法,你会建议我用什么方法来进行单元测试? - MarAja
比较集合相等性,set(my_method()) == {A(...), ...} - jonrsharpe
是的,但我的意思是使用unittest模块,我应该使用unittest.TestCase类中的方法吗? - MarAja
然后只需要使用assertEqual(不需要直接使用“types”方法),但我建议使用py.test - jonrsharpe
2个回答

5

我不确定如何实现可扩展的eq,但你可以尝试以下方法:

import unittest

class A:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __eq__(self, other):
        return self.a == other.a and self.b == other.b and self.c == other.c


a1, a2, a3 = ('a1', 'a2', 'a3')
b1, b2, b3 = ('b1', 'b2', 'b3')
c1, c2, c3 = ('c1', 'c2', 'c3')

def my_method():
    return [
        A(a1, b1, c1),
        A(a2, b2, c2),
        A(a3, b3, c3)
    ]

class BasicsTestCase(unittest.TestCase):
    def test_list_of_objects(self):
        self.assertListEqual(my_method(), [A(a1, b1, c1), A(a2, b2, c2),  A(a3, b3, c3)])

不过,如果my_method()中实际存在错误,那么解析结果可能并不容易,所以这只是一个快速而粗略的解决方案...


好的,我将jonrsharpe建议使用集合(因为元素的顺序无关紧要)与这个解决方案结合起来。我实现了__eq__和__hash__,它运行良好。谢谢。 - MarAja

3
actual = my_method() 
expected = [A(a1, b1, c1), A(a2, b2, c2), A(a3, b3, c3)]
self.assertListEqual(list(map(vars, expected)), list(map(vars, actual)))

你可以将 var 应用于列表中的元素。 另外需要注意的是,assert() 的参数正确顺序应该是 (expected, actual) 而不是 (actual, expected)。这个顺序很重要,因为在测试失败时,如果顺序错误,错误消息将会是错误的。

如何对具有浮点值的两个列表进行单元测试? - Devharsh Trivedi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接