Assert an integer is within range

Question:

I am writing some unittests in python that are testing if I receive an integer. However sometimes this integer can be off by 1 or 2 and I don’t really care. Essentially I want to be able to assert that the received integer is within a certain range, something like:

self.assertBetween(998, 1000, my_integer)

Is there an accepted way of doing this? Or will I have to do something like this:

self.assertTrue(998 <= my_integer)
self.assertTrue(my_integer <= 1000)

EDIT
The answers so far suggest:

self.assertTrue(998 <= my_integer <= 1000)

Is there any benefit of this over my example with 2 asserts?

Asked By: Yep_It's_Me

||

Answers:

You can use a “chained comparison“:

self.assertTrue(998 <= my_integer <= 1000)
Answered By: John Zwinck
self.assertTrue(998 <= my_integer <= 1000)
Answered By: saulspatz

Python has a built in function you may use for this: assertAlmostEqual.

self.assertAlmostEqual(myinteger, 999, delta=1)
# is equivalent to
self.assertTrue(998 <= myinteger <= 1000)
# ... but gives better error messages.

The optional parameter delta specifies the allowed distance from the value you’re testing.

Answered By: Teodor

I don’t think it’s a good idea to use assertTrue with comparison inside –
that way you lose any information in FAIL message:

AssertionError: False is not true

Which is not helpful at all and you’re basicaly back to “raw” assert and you are losing a lot of unittest‘s methods benefits.

I would recommend either:

Creating your own custom assert

in which you can print more meaningful message. For example:

import unittest

class BetweenAssertMixin(object):
    def assertBetween(self, x, lo, hi):
        if not (lo <= x <= hi):
            raise AssertionError('%r not between %r and %r' % (x, lo, hi))

class Test1(unittest.TestCase, BetweenAssertMixin):
    def test_between(self):
        self.assertBetween(999, 998, 1000)

    def test_too_low(self):
        self.assertBetween(997, 998, 1000)

    def test_too_high(self):
        self.assertBetween(1001, 998, 1000)

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

then you’ll have following output (shortened):

======================================================================
FAIL: test_too_high (__main__.Test1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "example.py", line 19, in test_too_high
    self.assertBetween(1001, 998, 1000)
  File "example.py", line 8, in assertBetween
    raise AssertionError('%r is not between %r and %r' % (x, lo, hi))
AssertionError: 1001 is not between 998 and 1000
======================================================================
FAIL: test_too_low (__main__.Test1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "example.py", line 16, in test_too_low
    self.assertBetween(997, 998, 1000)
  File "example.py", line 8, in assertBetween
    raise AssertionError('%r is not between %r and %r' % (x, lo, hi))
AssertionError: 997 is not between 998 and 1000
----------------------------------------------------------------------

Or use assertLessEqual and assertGreaterEqual

if you don’t want custom assert (which does add another traceback record and several lines of code):

...
def test_no_custom_assert(self):
    my_integer = 100
    self.assertGreaterEqual(my_integer, 998)
    self.assertLessEqual(my_integer, 1000)
...

which is a bit longer (it may be shorter in total than adding custom assert if it’s used only once) than assertTrue(998 <= my_integer <= 1000) but you’ll still get nice fail messages (also without additional traceback record):

======================================================================
FAIL: test_no_custom_assert (__main__.Test1)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "example.py", line 23, in test_no_custom_assert
    self.assertGreaterEqual(my_integer, 998)
AssertionError: 100 not greater than or equal to 998
Answered By: Jan Spurny