Using assertions

Published

2023-08-01

Using assertions to test your code

Many languages, Python included, allow for assertions or assert statements. These are used to verify things you believe should be true about some condition or result. By making an assertion, you’re saying “I believe x to be true”, whatever x might be. Assertions are a powerful tool for verifying that a function or program actually does what you expect it to do.

Python provides a keyword, assert which can be used in assert statements. Here are some examples:

Let’s say you have a function which takes a list of items for some purchase and applies sales tax. Whatever the subtotal might be, we know that the sales tax must be greater than or equal to zero. So we write an assertion:

sales_tax = calc_sales_tax(items)
assert sales_tax >= 0

If sales_tax is ever negative (which would be unexpected), this statement would raise an AssertionError, informing you that something you believed to be true, was not, in fact, true. This is roughly equivalent to

if sales_tax < 0:
    raise AssertionError

but is more concise and readable.

Notice that if the assertion holds, no exception is raised, and the execution of your code continues uninterrupted.

Here’s another example:

def calc_hypotenuse(a, b):
    """Given two legs of a right triangle, return the
    length of the hypotenuse. """
    assert a >= 0
    assert b >= 0
    
    return math.sqrt(a ** 2 + b ** 2)

What’s going on here? This isn’t data validation. Rather, we’re documenting conditions that must hold for the function to return a valid result, and we ensure that the program will fail if these conditions aren’t met. We could have a degenerate triangle, where one or both legs have length zero, but it cannot be the case that either leg has negative length. This approach has the added benefit of reminding the programmer what conditions must hold in order to ensure correct behavior.

Judicious use of assertions can help you write correct, robust code.

Adding friendly messages

Python’s assert allows you to provide a custom message in the event of an AssertionError. The syntax is simple,

assert 1 + 1 == 2, "Something is horribly wrong!"

Some caveats

It’s important to understand that assert is a Python keyword and not the name of a built-in function. This is correct:

assert 0.0 <= x <= 1.0, "x must be in [0.0, 1.0]"

but this is not

assert(0.0 <= x <= 1.0, "x must be in [0.0, 1.0]")

Why? This will treat the tuple

(0.0 <= x <= 1.0, "x must be in [0.0, 1.0]")

as what is being asserted. But non-empty tuples are truthy, and so this will never result in an AssertionError, no matter what the value of x!

Let’s test it

>>> x = -42
>>> assert(0.0 <= x <= 1.0, "x must be in [0.0, 1.0]")
<stdin>:1: SyntaxWarning: assertion is always true, 
        perhaps remove parentheses?
>>>

However, this works as intended

>>> x = -42
>>> assert 0.0 <= x <= 1.0, "x must be in [0.0, 1.0]"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: x must be in [0.0, 1.0]
>>> 

and if x is in the indicated interval, all is well.

>>> x = 0.42
>>> assert 0.0 <= x <= 1.0, "x must be in [0.0, 1.0]"
>>>

(Notice the >>> at the end of the snippet above, indicating that the assertion has passed and is thus silent.)

You should try adding assertions to your code. In fact, the NASA/JPL Laboratory for Reliable Software published a set of guidelines for producing reliable code, and one of these is “Use a minimum of two runtime assertions per function.”1

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).

Footnotes

  1. G.J. Holzmann, 2006, “The Power of 10: Rules for Developing Safety-Critical Code”, IEEE Computer, 39(6). doi:10.1109/MC.2006.212.↩︎