Testing Python

Ovid on 2003-04-13T20:24:46

Once again, I'm playing with another language. This time, I decided to put a fair amount of effort into learning Python. After returning the book I bought two days ago after discovering it was out of date, I simply grabbed the latest docs from the Python site and decided to sit down and start coding. Naturally, the first thing I wanted to do was learn how to write tests. I watched how our Python programmer at work wrote tests and I was surprised at how much code he had to write for it, so I started searching for Python testing frameworks myself. That's when I discovered Python's unittest. Here's how to write two tests:

import unittest

class SimpleWidgetTestCase(unittest.TestCase):
    def setUp(self):
        self.widget = Widget("The widget")

class DefaultWidgetSizeTestCase(SimpleWidgetTestCase):
    def runTest(self):
        self.failUnless(self.widget.size() == (50,50),
                        'incorrect default size')

class WidgetResizeTestCase(SimpleWidgetTestCase):
    def runTest(self):
        self.widget.resize(100,150)
        self.failUnless(self.widget.size() == (100,150),
                        'wrong size after resize')

It appears that for each test case, I have to define a new class and then run tests on it. I'm totally blown away by the amount of work involved and all I want to do is write simple tests. While I realize that I might be reinventing the wheel, I decided that a great way to learn Python would be to write my own testing framework modelled after Perl's Test::More.

import mytest
import Widget
t = mytest.test(count = 2)
widget = Widget("The widget)
t.match(widget.size(), (50,50),
        name="Default size should be correct")
widget.resize(100,150)
t.match(widget.size(), (100,50),
        name="... and resize should work")

That would produce output like:

1 .. 2
ok 1 - Default size should be correct
ok 2 - ... and resize should work

Results:

Success: 2
Failure: 0
Percent passed: 100.00

So far, that's much more like what I'm used to seeing and it was pretty easy to implement (though I have a lot of work to do). However, as I get further into Python, I can only assume that they have reasons for why they're doing things their way. I don't understand why they lack test counts, for example. Perhaps procedural tests (even if implemented through an object instance) simply don't fit the Python model very well, but we'll see what happens.

And for my first actual test program:

import test

t = test.test(count=4)

t.ok(1, name='1 should be true')
t.match(2,2,name="2 should equal 2")
t.no_match(2,3, name="two should not equal three")
t.match(2,3, name="two should not equal three")
t.match(2,2)
t.ok(not None, name="'None' should evaluate as false")

I get the following results:

1 .. 4
ok 1 - 1 should be true
ok 2 - 2 should equal 2
ok 3 - two should not equal three
not ok 4 - two should not equal three
        Expected: (2)
        Got:      (3)
ok 5 - No test name assigned
ok 6 - 'None' should evaluate as false

Results:

Dubious test results. 4 tests requested and 6 tests ran
Success: 5
Failure: 1
Percent passed: 83.33

Next I need to add many more testing methods and try my hand at producing a test harness. I may very well scrap all of this in the end but it's a great learning experience.


Hmm...

pdcawley on 2003-04-13T20:46:57

Hmm... a quick look at the PyUnit home page (it's on sourceforge) implies that you don't need a class per test, you just have to make sure that all the tests you want to run with a given fixture (set up using the setUp method) match /^test/, which is very much in keeping with the original sunit way of doing things.

It's worth persevering with as a testing framework, honest. Once you get the hang of it, you'll find something like it for almost every OO language you care to think about.

Re:Hmm...

Ovid on 2003-04-13T21:06:58

Ah, that has better testing information that the docs that I grabbed. Looks like it's fairly useful. Thanks!

xUnit framework

jonasbn on 2003-04-14T06:35:21

It is the normal structure of the xUnit based test frameworks. I use Nunit (.NET unit testing) at work.

But it is better than nothing. I still need to convince all my colleagues of the necessity of writing unit-tests.

And I think you can easily build a lighter framework with the building blocks provided xUnit based framework.

BTW: there is a xUnit framework for Perl aswell, check perlUnit also at sourceforge.

Re:xUnit framework

pdcawley on 2003-04-14T08:32:32

Speaking as someone who used to be the maintainer of this package, I've switched to using Test::Unit, which place nicely with all the other testing frameworks that are built on top of Test::Builder. It does a few things different if you're used to the xUnit way of things, but I find it to be a really good synthesis of approaches.