What is the difference between assertIs and assertTrue in unittest module, when these methods are applied on True values?

Viewed 379

My working environment:

OS: Ubuntu 18.04 (64 bits)
Python version: 3.8.0 (64 bits)

I've a question about the unittest documentation, more precisely, the difference between assertTrue and assertIs methods. Here is what the online documentation says:

https://docs.python.org/3/library/unittest.html

assertTrue(expr, msg=None)

assertFalse(expr, msg=None)

Test that expr is true (or false).

Note that this is equivalent to bool(expr) is True and not to expr is True (use assertIs(expr, True) for the latter).

I don't really understand the difference, that is, in the case where I have a boolean type with a True value, then why should I use assertIs instead of assertTrue? Given that bool(True) is True also returns the True boolean value I don't see the difference and impact on tests. I'd appreciate if you could kindly make some clarification.

2 Answers

To answer the question you have to understand the difference between is and == comparison operators, imagine you have two different boys, but they are both Peters, they have the same name so == will give you true, but is will give you False, because they are not one person.

import unittest


class MyClass:
    def __init__(self, value):
        self.value = value

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


class TestStringMethods(unittest.TestCase):

    def test_your_func(self):
        x = MyClass(5)
        y = MyClass(5)
        z = x
        print(x is y)  # False x is not y, they are separate object
        print(x == y)  # True 5 == 5 
        print(x is z)  # True, because z is the reference to the same object
        print(z == y)  # True 5 == 5
        # self.assertIs(x, y)  # if you uncomment the line you'll get error
        self.assertIs(x, z)


if __name__ == '__main__':
    unittest.main()

As per AssertTruem it has absolutely different purpose to use, e.g. if []: is False and if [1] is True.

You are basically right - in most cases in tests you will probably use assertTrue for the check instead of assertIs(True).

The only really useful case where you actually need assertIs(True) would be if you want to check that the checked expression actually returns a bool value, e.g.:

def test_bool(self):
    a = True
    b = 1
    self.assertTrue(a)
    self.assertIs(a, True)
    self.assertTrue(b)
    self.assertIsNot(b, True)

This could be interesting if you have a function that may return values of different types, and you want to ensure that it returns a concrete bool value. Consider a (nonsense) function:

def fct(param):
    if param < 0:
        return False
    if param > 0:
        return True
    return 42

...

def test_fct(self):
    assertTrue(fct(1))  # will not ensure that it returns True
    assertTrue(fct(0))  # also passes
    assertIs(True, fct(1))  # passes as intended
    assertIs(True, fct(0))  # fails, as it should

It can also help to ensure that your tested function that is supposed to return a bool value actually does that (and not just some value that would evaluate to True or False, like None or a number, due to some bug).

This all works of course because (like None), True and False are singleton objects, e.g. there is always only one of each of them.

Related