unittest introduction

The unittest test framework is python’s xUnit style framework.
It is a standard module that you already have if you’ve got python version 2.1 or greater.
In this post, I’ll cover the basics of how to create and run a simple test using unittest.
Then I’ll show how I’m using it to test markdown.py.

Overview of unittest

The unittest module used to be called PyUnit, due to it’s legacy as a xUnit style framework.
It works much the same as the other styles of xUnit, and if you’re familiar with unit testing in other languages, this framework (or derived versions), may be the most comfortable for you.

The standard workflow is:
1. You define your own class derived from unittest.TestCase.
2. Then you fill it with functions that start with ‘test_’.
3. You run the tests by placing unittest.main() in your file, usually at the bottom.

One of the many benifits of unittest, that you’ll use when your tests get bigger than the toy examples I’m showing on this blog, is the use of ‘setUp’ and ‘tearDown’ functions to get your system ready for the tests.

Like the doctest introduction, I’ll run through a simple example first, then show how I’m using unittest for testing markdown.py.

unittest example

Using the same unnecessary_math.py module that I wrote in the
doctest intro, here’s some example test
code to test my ‘multiply’ function.

test_um_unittest.py:

In this example, I’ve used assertEqual(). The unittest framework has a whole bunch of assertBlah() style functions like assertEqual(). Once you have a reasonable reference for all of the assert functions bookmarked, working with unnittest is pretty powerful and easy.

Aside from the tests you write, most of what you need to do can be accomplished with the test fixture methods such as setUp, tearDown, setUpClass, tearDownClass, etc.

Running unittests

At the bottom of the test file, we have this code:

This allows us to run all of the test code just by running the file.
Running it with no options is the most terse, and running with a ‘-v’ is more verbose, showing which tests
ran.

Test discovery

Let’s say that you’ve got a bunch of test files. It would be annoying to have to run each test file separately. That’s where test discovery comes in handy.

In our case, all of my test code (one file for now) is in ‘simple_example’.
To run all of the unittests in there, use python -m unittest discover simple_example, with or without the ‘-v’, like this:

unittest example with markdown.py

Now, I’ll throw unittest at my markdown.py project.
This is going to be pretty straightforward, as the tests are quite similar to the doctest versions, just formatted with all of the unittest boilerplate stuff, especially since I don’t need to make use of startUp or tearDown fixtures.

test_markdown_unittest.py:

Testing markdown.py

And now we can see that everything is failing (as expected).

One interesting thing to note as compared to doctest. Only actual tests are counted.
I have 3 tests. And unittest gets that right.
Doctest lists 4 tests, with one of them passing. What’s the 4th? It’s the import statement.
Every statement is counted in doctest, so the counts are quite a bit wacky, if you ask me.
The counts are way more meaningful in unittest.

More unittest info

The python.org page on unittest is a great source for information on unittest.
If you’ve got another favorite tutorial or reference for unittest, please leave a comment.

Also, the code shown here is available on github.com/variedthoughts/markdown.py

Next

Now that the basics of doctest and unittest are done, I’ll get into some of the real fun by exploring nose, then py.test.
Then, before getting onto some other fun topics, I probably should get my markdown.py script to do something.
In the process of doing that, I’ll probably have at least one post talking about my use of regular expressions in python.

Feedback

I’ve received some feedback through email and other means.
Thank you to everyone that participates in this discussion.

If you are not comfortable leaving comments on a post, you can use the contact form.
If the contact form doesn’t work for you, or you just don’t like contact forms, you can email me directly.

The email I have set up for this blog is
brian AT python testing DOT net (no spaces, of course)

I have a handful of ideas for future blog posts, so I cannot promise that I will cover all of the suggestions that people give me, but I will try to fit them in, especially if I can learn something in the process.

Thanks for reading. Keep in touch!

If you like this…

Get notified of new posts, delivered to your inbox. No spam. Not very frequent.

Comments

  1. chandrika says

    I just started writing unit test. Your explanation helped me lot. Thanks for posting such a wonderful piece.

      • says

        Hi Brian

        Thanks for the post. Is it possible to fire up the pyUnit test from a python application.

        I have created a view in wxPython for selecting the test cases , hence I would like to start the respective testcases or test class,w.r.t the selection been made.

        Can you kindly suggest how this can be done.

        You help is much appreciated in this regard.

        Thanks

        • says

          You can call unittest.main() from any python file.
          It doesn’t have to be just the module where the tests are located.
          Take a look at the documentation and see if that helps.

          I’ve never tried what you are attempting, though.
          Please let us know if you succeed in your endeavors.
          Sounds cool. I’d like to try it when you’re finished.

  2. patrick says

    I looked at the Python documents, so forgive if its not clear, but how does the unitttest.testcase class that you call from “__main__” know to call the methods of the subclass “TestUM” that you defined?

    • says

      The common idiom in unittest files is to have something like this:

      There are lots of parameters you can have for unittest.main().
      More info can be found here.

      However, the defaults for those parameters are set up such that all of the methods that start with ‘test_’ that are part of any class derived from unittest.TestCase that are found within the current module are run.

      Quite handy.

Leave a Reply