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

6

11

In my test case, I assume that if two values are NaN then they are equal. What is the way to express it using unittest assertions? The two common functions presented below are not handling this case.

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

A solution that is working for me right now is using a boolean expression inside assertTrue:

self.assertTrue(v1 == v2 or (np.isnan(v1) and np.isnan(v2))
Hitandrun answered 7/8, 2018 at 13:49 Comment(3)
I'd probably write my own assertion method, e.g. assertBothNan, or override assertEquals if you always want that behaviour. As to how you check if a value is NaN: https://mcmap.net/q/420894/-how-to-check-if-value-is-nan-in-unittest/3001761Ossa
This will not work, v1==v2 will be False. You should check that both are Nan separately and then write your own assertion method.Jaclyn
That's why I am looking for a solution covering a case when both values are not NaN and when they are both NaN. I will understand if there is only a complex boolean expression available at the moment.Dalton
T
16

You could use:

numpy.testing.assert_equal(v1, v2)

From 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.

It throws AssertionError when the values are not equal and it should work fine with pytest, but it may not be a good fit for unittest tests.

Another option is:

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

but obviously it's a replacement for math.isclose, not for ==.

Torrens answered 4/3, 2020 at 18:30 Comment(1)
note that this does not work for 'object' dtypes: e.g. np.array(["hello",np.nan],dtype='object') raises an errorCalisa
J
5

It does not make sense to check two NaNs for equality. The best you could do is to check it in a different way, for example:

check = numpy.isnan(v1) and numpy.isnan(v2)
self.assertTrue(check)
Jaclyn answered 7/8, 2018 at 13:55 Comment(0)
F
3

You can use math.isnan

self.assertTrue(math.isnan(v1) and math.isnan(v2))
Firstly answered 7/8, 2018 at 14:5 Comment(0)
A
1

You could check if each of them is NaN separately. To do that, I suggest using the following 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

It would be as easy as:

v1 = np.nan
v2 = np.nan
self.assertIsNaN(v1)
self.assertIsNaN(v2)
Assumptive answered 7/8, 2018 at 14:2 Comment(0)
J
1

A standard way of checking for nans is

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

i.e. something that is not equal to itself, e.g:

>>> n = float('nan')
>>> n != n
True
Julian answered 19/2, 2020 at 23:12 Comment(0)
W
1

For comparing python data structures (e.g. with assertListEqual/assertDictEqual) which might contain NaN values, the following expression works in place of NaN constant:

pytest.approx(np.nan, nan_ok=True)
Witching answered 4/7 at 16:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.