It’s easy to accidentally write Python assert statements that always evaluate to true. Here’s how to avoid this mistake and catch bad assertions as part of your continuous integration build.

Asserts that are always true

There’s an easy mistake to make with Python’s assert :

When you pass it a tuple as the first argument, the assertion always evaluates as true and therefore never fails.

To give you a simple example, this assertion will never fail:

assert ( 1 == 2 , 'This should fail' )

Especially for developers new to Python this can be a surprising result.

Let’s take a quick look at the syntax for Python’s assert statement to find out why this assertion is bogus and will never fail.

Here’s the syntax for assert from the Python docs:

assert_stmt ::= "assert" expression1 ["," expression2]

expression1 is the condition we test, and the optional expression2 is an error message that’s displayed if the assertion fails.

At execution time, the Python interpreter transforms each assert statement into the following:

if __debug__ : if not expression1 : raise AssertionError ( expression2 )

Let’s take the broken example assertion and apply the transform.

assert ( 1 == 2 , 'This should fail' )

becomes the following:

if __debug__ : if not ( 1 == 2 , 'This should fail' ): raise AssertionError ()

Now we can see where things go wrong.

Because assert is a statement and not a function call, the parentheses lead to expression1 containing the whole tuple (1 == 2, 'This should fail') .

Non-empty tuples are always truthy in Python and therefore the assertion will always evaluate to true, which is maybe not what we expected.

This behavior can make writing multi-line asserts error-prone. Imagine we have the following assert statement somewhere in our test code:

assert ( counter == 10 , 'It should have counted all the items' )

This test case would never catch an incorrect result. The assertion always evaluates to True regardless of the state of the counter variable.

Pytest encourages you to use plain assert statements in unit tests instead of the assertEquals , assertTrue , …, assertXYZ methods provided by the unittest module in the standard library.

It’s relatively easy to accidentally write bad multi-line asserts this way. They can lead to broken test cases that give a falls sense of security in our test code.