unittest - 如何断言两个可能的 NaN 值是否相等

unittest - how to assert if the two possibly NaN values are equal

在我的测试用例中,我假设如果两个值是 NaN 那么它们是相等的。使用 unittest 断言表达它的方式是什么?下面介绍的两个常用函数不处理这种情况。

v1 = np.nan
v2 = np.nan
self.assertEquals(v1, v2)
self.assertTrue(v1 == v2)

目前对我有用的解决方案是在 assertTrue:

中使用布尔表达式
self.assertTrue(v1 == v2 or (np.isnan(v1) and np.isnan(v2))

检查两个 NaN 是否相等没有意义。你能做的最好的就是用不同的方式检查它,例如:

check = numpy.isnan(v1) and numpy.isnan(v2)
self.assertTrue(check)

您可以分别检查它们是否均为 NaN。为此,我建议使用以下 class:

import math


class NumericAssertions:
    """
    This class is following the UnitTest naming conventions.
    It is meant to be used along with unittest.TestCase like so :
    class MyTest(unittest.TestCase, NumericAssertions):
        ...
    It needs python >= 2.6
    """

    def assertIsNaN(self, value, msg=None):
        """Fail if provided value is not NaN"""
        standardMsg = "%s is not NaN" % str(value)
        try:
            if not math.isnan(value):
                self.fail(self._formatMessage(msg, standardMsg))
        except:
            self.fail(self._formatMessage(msg, standardMsg))

    def assertIsNotNaN(self, value, msg=None):
        """Fail if provided value is NaN"""
        standardMsg = "Provided value is NaN"
        try:
            if math.isnan(value):
                self.fail(self._formatMessage(msg, standardMsg))
        except:
            pass

这会很简单:

v1 = np.nan
v2 = np.nan
self.assertIsNaN(v1)
self.assertIsNaN(v2)

您可以使用math.isnan

self.assertTrue(math.isnan(v1) and math.isnan(v2))

检查 nan 的标准方法是

assert (v1 != v1) and (v2 != v2)

即不等于自身的东西,例如:

>>> n = float('nan')
>>> n != n
True

您可以使用:

numpy.testing.assert_equal(v1, v2)

来自docs

This function handles NaN comparisons as if NaN was a “normal” number. That is, no assertion is raised if both objects have NaNs in the same positions. This is in contrast to the IEEE standard on NaNs, which says that NaN compared to anything must return False.

当值不相等时它会抛出 AssertionError,它应该可以很好地与 pytest 一起工作,但它可能不适合单元测试。

另一种选择是:

numpy.isclose(v1, v2, equal_nan=True)

但显然它是 math.isclose 的替代品,而不是 ==