python - 在 Python 中测试实际相等性

标签 python unit-testing equality python-2.x

我正在编写一个模拟某个库的 Python2 模块。结果可能是floatintlongunicodestrtuplelist 和自定义对象。列表可能不包含列表,但它们可能包含元组。元组可能不包含列表或元组。否则,列表和元组可能包含上面列出的任何其他类型。

(实际上,模块不应该返回longstr,但如果返回,它们应该被捕获并报告为不同的时候分别与 intunicode 相比。)

我正在编写一个测试程序,根据我的模块尝试模拟的库的已知答案检查结果。显而易见的答案是测试值和类型,但我面临的一个问题是在极端情况下,可能要测试的结果是 -0.0 (应该与 区分开来0.0) 和 NaN(不是数字 - float 可以采用的值)。

但是:

>>> a = float('nan')
>>> b = float('nan')
>>> a == b
False
>>> c = float('-0.0')
>>> c
-0.0
>>> d = 1.0 - 1.0
>>> c == d
True

is 运算符没有一点帮助:

>>> a is b
False
>>> d is 0.0
False

repr 帮助:

>>> repr(a) == repr(b)
True
>>> repr(c) == repr(d)
False
>>> repr(d) == repr(0.0)
True

但仅在一定程度上,因为它对对象没有帮助:

>>> class e:
...   pass
... 
>>> f = e()
>>> g = e()
>>> f.x = float('nan')
>>> g.x = float('nan')
>>> f == g
False
>>> repr(f) == repr(g)
False

这虽然有效:

>>> repr(f.__dict__) == repr(g.__dict__)
True

但是它对元组和列表失败了:

>>> h = [float('nan'), f]
>>> i = [float('nan'), g]
>>> h == i
False
>>> repr(h) == repr(i)
False
>>> repr(h.__dict__) == repr(i.__dict__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__dict__'

看来我很接近,所以我需要知道:

  1. 是否有一种更简单的方法来检查实际的相等性,并且没有转换为字符串的负担?
  2. 如果没有,我将如何比较包含对象的列表或元组?

编辑:明确地说,我所追求的是完整的比较功能。我的测试函数大致如下所示:

>>> def test(expression, expected):
...   actual = eval(expression)
...   if not reallyequal(actual, expected):
...     report_error(expression, actual, expected)

我的问题是 reallyequal() 应该是什么样子。

编辑 2: 我找到了 Python 标准模块 unittest 但不幸的是没有一个检查涵盖这个用例,所以看来如果我打算使用它,我应该使用像 self.assertTrue(reallyequal(actual, expected)) 这样的东西。

我真的很惊讶很难进行单元测试,包括嵌套在结果中的预期 NaN 和负零。我仍在使用 repr 解决方案,这是一个半解决方案,但我对其他想法持开放态度。

最佳答案

这是一种实现方式:

def really_equal(actual, expected, tolerance=0.0001):
    """Compare actual and expected for 'actual' equality."""

    # 1. Both same type?
    if not isinstance(actual, type(expected)):
        return False

    # 2. Deal with floats (edge cases, tolerance)
    if isinstance(actual, float):
        if actual == 0.0:
            return str(actual) == str(expected)
        elif math.isnan(actual):
            return math.isnan(expected)
        return abs(actual - expected) < tolerance

    # 3. Deal with tuples and lists (item-by-item, recursively)
    if isinstance(actual, (tuple, list)):
        return all(really_equal(i1, i2) for i1, i2 in zip(actual, expected))

    # 4. Fall back to 'classic' equality
    return actual == expected

“经典”平等的一些极端情况:

>>> float('nan') == float('nan')
False
>>> really_equal(float('nan'), float('nan'))
True

>>> 0.0 == -0.0
True
>>> really_equal(0.0, -0.0)
False

>>> "foo" == u"foo"
True
>>> really_equal("foo", u"foo")
False

>>> 1L == 1
True
>>> really_equal(1L, 1)
False

类应该实现它们自己的__eq__“魔术方法”来确定两个实例是否相等——它们将落入#4并在那里进行比较:

>>> class Test(object):

    def __init__(self, val):
        self.val = val

    def __eq__(self, other):
        return self.val == other.val


>>> a = Test(1)
>>> b = Test(1)
>>> really_equal(a, b)
True

关于python - 在 Python 中测试实际相等性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24268397/

相关文章:

Heroku 上的 Python 和 Node.js

c++ - 我应该将单元测试放在单独的库中吗?单独的子目录?

rust - 断言特征对象的相等性?

避免指针比较的 C++ 技巧

python - 在 Python 中检测是否使用系留电话连接到互联网

python - 从 bytearray 转换为 bytes 会产生一个副本吗?

unit-testing - OpenCover 的运行时间比 nunit-console 长得多

unit-testing - Grails 测试域模型 - 模拟

具有相同长度但类型不同长度表达式的向量之间的相等性

python - 改进我的项目 euler p12 的代码。在 Python 中