Up to this point we have mostly tested our software using Boolean conditions. For example, "assert double(2) == 4". This is very flexible, but it has some shortcomings as well.
First, think about what happens when a test fails, we know it failed (since the expression was false) but we don't know how it failed. For example, did "double(2)" return 5? Or maybe 3? A negative number? Maybe it returned something that isn't even an integer? It would be nice if the test would give us some hint as to what went wrong when it fails. If we created this ourselves it might look a little like this:
def assert_equal(actual, expected):
if actual != expected:
raise AssertionError('%s does not equal %s' % (actual, expected))
Now we can write our original statement as "assert_equal(double(2), 4)", and if the two values aren't equal we'll find out what the actual value returned from "double" was, which can help us debug.
In practice, most languages have one or more libraries with functions more or less like the one above. In fact, in most cases we have access to a huge number of these functions for all kinds of assertions: equality, inequality, value contained in a list, and so on. Practically anything we might want to check about the results of our code or program is likely to be encapsulated by a special assertion, and if it isn't, we can always create our own.
The test framework included in the Python standard library is called "unittest" (it can technically be used for more than just unit testing, but it is primarily aimed at unit testing).