The unittest Module

Simplest Example

import unittest
class MyTestCase(unittest.TestCase):
    def runTest(self):
        self.assertEqual(1, 2)
c = MyTestCase()
unittest.TextTestRunner().run(c)
FAIL: runTest (__main__.MyTestCase)
---------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/x.py", line 6, in runTest
    self.assertEqual(1, 2)
AssertionError: 1 != 2

Using a Fixture

Problems …

  • Cleanup after test failure

  • Setup before test begin

  • ⟶ formalize (prepare and release) a controlled environment for the test body

class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.__db = create_database()
        fill_test_data(self.__db)
    def tearDown(self):
        remove_database(self.__db)
    def runTest(self):
        ...
c = MyTestCase()
unittest.TextTestRunner().run(c)

Multiple Test Cases With Same Fixture

  • A single runTest() method is not sufficient in most cases

    • A fixture’s purpose is to serve multiple related test cases

  • ⟶ test case with multiple test methods

  • Test Suite

class MyTestCase(unittest.TestCase):
    def setUp(self): ...
    def tearDown(self): ...
    def testFeature1(self): ...
    def testFeature2(self): ...
suite = unittest.TestSuite()
suite.addTest(MyTestCase('testFeature1')
suite.addTest(MyTestCase('testFeature2')
unittest.TextTestRunner().run(suite)

Auto Recognizing Test Methods

Problems:

  • Two steps: write test case and add test case

  • ⟶ /me writes test, but forgets to add to suite

  • Lost Test Syndrome

class MyTestCase(unittest.TestCase):
    def setUp(self): ...
    def tearDown(self): ...
    def testFeature1(self): ...
    def testFeature2(self): ...
suite = unittest.TestLoader().\
    loadTestsFromTestCase(MyTestCase)
unittest.TextTestRunner().run(suite)

The Meat of a Test

Enough structure, now for the real test code …

class MyTestCase(unittest.TestCase):
    def testSomething(self):
        self.failIf(1 == 2, "OMG!")

There’s more:

  • failUnless(2 == 2)

  • failUnlessEqual(2, 2)

  • failIfEqual(2, 3)

  • failUnlessAlmostEqual(2.12345, 2.123, 3)

  • failUnlessRaises(IOError, file('/'))

Recommendations

A few recommendations, out of personal experience …

  • If tests become a burden, then you’ve messed it up!

  • Tests should live near the code

    • … but not in it

  • Code must not use test code!

  • Structure your tests (test suites) like your package structure

  • Test First Development - adding tests afterwards is rarely fun

  • There is no Design for Testability - sound design is always testable.

  • It’s easy to become an addict!