Assertions

Assertions are the mechanism we use to tell unittest what the important outcomes of the test are. By using appropriate assertions, we can tell unittest exactly what to expect from each test.

The assertTrue method

When we call self.assertTrue(expression), we're telling unittest that the expression must be true in order for the test to be a success.

This is a very flexible assertion, since you can check for nearly anything by writing the appropriate Boolean expression. It's also one of the last assertions you should consider using, because it doesn't tell unittest anything about the kind of comparison you're making, which means that unittest can't tell you clearly what's gone wrong if the test fails.

For example, consider the following test code containing two tests that are guaranteed to fail:

from unittest import TestCase

class two_failing_tests(TestCase):
    def test_one_plus_one_equals_one_is_true(self):
        self.assertTrue(1 == 1 + 1)

    def test_one_plus_one_equals_one(self):
        self.assertEqual(1, 1 + 1)

It might seem that the two tests are interchangeable, since they both test the same thing. Certainly they'll both fail (or, in the unlikely event that one equals two, they'll both pass), so why prefer one over the other?

Run the tests and see what happens (and also notice that the tests were not executed in the same order as we wrote them; the tests are totally independent of each other, so that's okay, right?).

Both the tests fail, as expected, but the test that uses assertEqual tells us:

AssertionError: 1 != 2

The other one says:

AssertionError: False is not true

It's pretty clear which of these outputs is more useful in this situation. The assertTrue test was able to correctly determine that the test should fail, but it didn't know enough to report any useful information about why it failed. The assertEqual test, on the other hand, knew first of all that it was checking whether the two expressions were equal, and second it knew how to present the results so that they would be most useful: by evaluating each of the expressions that it was comparing and placing a != symbol between the results. It tells us both which expectation failed, and what the relevant expressions evaluate to.

The assertFalse method

The assertFalse method will succeed when the assertTrue method will fail, and vice versa. It has the same limits in terms of producing useful output that assertTrue has, and the same flexibility in terms of being able to test nearly any condition.

The assertEqual method

As mentioned in the assertTrue discussion, the assertEqual assertion checks whether its two parameters are in fact equal, and reports a failure if they are not, along with the actual values of the parameters.

The assertNotEqual method

The assertNotEqual assertion fails whenever the assertEqual assertion would have succeeded, and vice versa. When it reports a failure, its output indicates that the values of the two expressions are equal, and provides you with those values.

The assertAlmostEqual method

As we've seen before, comparing floating point numbers can be troublesome. In particular, checking whether two floating point numbers are equal is problematic, because things that you might expect to be equal—things that, mathematically, are equal—may still end up differing down among the least significant bits. Floating point numbers only compare equal when every bit is the same.

To address this problem, unittest provides assertAlmostEqual, which checks whether the two floating point values are almost the same; a small amount of difference between them is tolerated.

Let's look at this problem in action. If you take the square root of seven, and then square it, the result should be seven. Here's a pair of tests that check this fact:

from unittest import TestCase

class floating_point_problems(TestCase):
    def test_square_root_of_seven_squared_incorrectly(self):
        self.assertEqual((7.0 ** 0.5) ** 2.0, 7.0)

    def test_square_root_of_seven_squared(self):
        self.assertAlmostEqual((7.0 ** 0.5) ** 2.0, 7.0)

The test_square_root_of_seven_squared_incorrectly method checks that The assertAlmostEqual method, which is true in reality. In the more specialized number system available to computers, though, taking the square root of 7 and then squaring it doesn't quite get us back to 7, so this test will fail. We will look more closely at this in a moment.

The test_square_root_of_seven_squared method checks The assertAlmostEqual method, which even the computer will find to be true, so this test should pass.

Unfortunately, floating point numbers (the representation of real numbers used by computers) are not precise, because the majority of numbers on the real number line cannot be represented with a finite, non-repeating sequence of digits, much less than a mere 64 bits. Consequently, what you get back from evaluating the mathematical expression in the previous example is not quite seven. It's good enough for government work though—or practically any other sort of work as well—so we don't want our test to quibble over that tiny difference. Because of this, we should habitually use assertAlmostEqual and assertNotAlmostEqual when we're comparing floating point numbers with equality.

Note

This problem doesn't generally carry over into other comparison operators. Checking whether one floating point number is less than the other, for example, is very unlikely to produce the wrong result due to insignificant errors. It's only in cases of equality that this problem bites us.

The assertNotAlmostEqual method

The assertNotAlmostEqual assertion fails whenever the assertAlmostEqual assertion would have succeeded, and vice versa. When it reports a failure, its output indicates that the values of the two expressions are nearly equal, and provides you with those values.

The assertIs and assertIsNot methods

The assertIs and assertIsNot methods have the same relationship with Python's is operator that assertEqual and assertNotEqual have to Python's == operator. What this means is that they check whether the two operands are (or are not) exactly the same object.

The assertIsNone and assertIsNotNone methods

The assertIsNone and assertIsNotNone methods are like assertIs and assertIsNot, except that they accept only one parameter that they always compare to None, rather than accepting two parameters and comparing them to each other.

The assertIn and assertNotIn methods

The assertIn method is used for checking container objects such as dictionaries, tuples, lists, and sets. If the first parameter is contained in the second, the assertion passes. If not, the assertion fails. The assertNotIn method performs the inverse check.

The assertIsInstance and assertNotIsInstance methods

The assertIsInstance method checks whether the object passed as the first parameter is an instance of the class passed as the second parameter. The assertNotIsInstance method performs the opposite check, ensuring that the object is not an instance of the class.

The assertRaises method

As always, we need to make sure that our units correctly signal errors. Doing the right thing when they receive good inputs is only half the job; they need to do something reasonable when they receive bad inputs, as well.

The assertRaises method checks whether a callable raises a specified exception when passed a specified set of parameters.

Note

A callable is a function, a method, a class, or an object of any arbitrary type that has a __call__ method.

This assertion only works with callables, which means that you don't have a way of checking whether other sorts of expressions raise an expected exception. If that doesn't fit the needs of your test, it's possible to construct your own test using the fail method, described below.

To use assertRaises, first pass the expected exception to it, then the callable, and then the parameters that should be passed to the callable when it's invoked.

Here's an example test using assertRaises. This test ought to fail, because the callable won't raise the expected exception. '8ca2' is a perfectly acceptable input to int, when you're also passing base = 16 to it. Notice that assertRaises will accept any number of positional or keyword arguments, and pass them on to the callable on invocation:

from unittest import TestCase

class silly_int_test(TestCase):
    def test_int_from_string(self):
        self.assertRaises(ValueError, int, '8ca2', base = 16)

When we run this test, it fails (as we knew it would) because int didn't raise the exception we told assertRaises to expect. The test fails and reports this as follows:

AssertionError: ValueError not raised by int

If an exception is raised, but it's not the one you told unittest to expect, then unittest considers that as an error. An error is different from a failure. A failure means that one of your tests has detected a problem in the unit being tested. An error means that there's a problem with the test itself.

The fail method

When all else fails, you can fall back on fail. When the code in your test calls fail, the test fails.

What good does that do? When none of the assert methods do what you need, you can instead write your checks in such a way that fail will be called if the test does not pass. This allows you to use the full expressiveness of Python to describe checks for your expectations.

Let's take a look at an example. This time, we're going to test on a less-than operation, which isn't one of the operations directly supported by an assert method. Using fail, it's easy to implement the test anyhow:

from unittest import TestCase

class test_with_fail(TestCase):
    def test_less_than(self):
        if not (2.3 < 5.6):
            self.fail('2.3 is not less than 5.6, but it should be')

Tip

If a particular comparison gets used repeatedly in your tests, you can write your own assert function for that comparison, using fail to report errors just as we did in the preceding example.

A couple of things to notice here. First of all, take note of the not in the if statement. Since we want to run fail if the test should not pass, but we're used to describing the circumstances when the test should succeed, a good way to write the test is to write the success condition, and then invert it with not. That way we can continue thinking in the way we're used to when we use fail. The second thing to note is that you can pass a message to fail when you call it; it will be printed out in unittest report of failed tests. If you choose your message carefully, it can be a big help.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.2.240