A tiny introduction to Python unit testing

12 May 2017

codepythontdd

As I go deeper and deeper into Python, lead by experiments with the Microbit, I thought it was about time I experimented with some tests. That should have been the first thing I did, right?

Well, on the microbit - an embedded device - it’s not easy to see whether a self-hosted test framework would be much use (or is it - I may revisit this again). For now, I’m going to concentrate on writing and running tests only on vanilla desktop machines.

To get started we need to have a test framework and Python has unittest. The shape of this module will be familiar to anyone who has used an xUnit kind of framework before. You need to create a class derived from unittest.TestCase and define methods that start with test within the class. setUp and tearDown methods are reserved by the framework to do preparation and clean up before and after each test.

Assertions

As you might expect from xUnit frameworks, assertions are the way to test your code. unittest provides some nicely familiar assertEqual, assertNotEqual, assertTrue, assertFalse among others. Be careful to use self.assert* to make sure that python knows which function you are invoking, otherwise you will get see something like:


NameError: global name 'assertEqual' is not defined

and your unit test will be failing for the wrong reason.

Code


import unittest

# All these tests will fail !
class TestMyCode(unittest.TestCase):

  def test_jimi_hendrix_lyrics(self):

    self.assertNotEqual(6, 9)
    self.assertEqual(6, 9)


  def test_black_is_white(self):

    self.assertTrue('black' == 'white')


  def test_up_is_down(self):

    self.assertFalse('up' != 'down')

Running


python -m unittest test_my_code

Of course, I have been a good red-green-refactor-er and written failing tests first. This is the output from running the tests:

results

Each failure shows you the title of the test that failed (which is why naming your tests descriptively is important), the line of the failing assertion and why the framework thought the test failed.

If you liked this post you can tweet it or follow me on Twitter!