A more complicated test

Remember, we have two tests to perform on the DocviewDoc class. It would be a bit messy and chaotic to write separate testcase classes for those two tests. Additionally, in many cases you will have to prepare an environment for those tests, and it would be a pity to duplicate that code across many test classes.

It is therefore possible to create more than one testing method for each testcase. For each test method a separate instance of the test object is created and added to the test suite. These methods customarily start with ‘check', but that's not necessary.

#
# dvt2.py - a simple test of instantiating a document
#
import sys
import unittest
from docviewdoc import DocviewDoc

class DocviewDocTestCase(unittest.TestCase):
    """DocviewDocTestCase test the DocviewDoc class.
    """
    def checkInstantion(self):
        """Check whether the document could be instantiated"""
        doc=None
        doc=DocviewDoc()
        except:
            self.fail("Could not instantiate document for reason: " +
                 sys.exc_info()[0])
        else:
            assert doc!=None, 'Could not instantiate DocviewDoc'

    def checkModifiable(self):
        """Check whether the document could be modified"""
        doc=DocviewDoc()
        doc.slotModify()
        assert doc.isModified(), 'Document could not be modified'

    def checkUniverse(self):
        """Check whether the universe is still sane"""
        try:
            val = 1 / 0
        except ZeroDivisionError:
            pass # all natural laws still hold
        else:
            fail ("The universe has been demolished and replaced with chaos.")

def suite():
    testSuite=unittest.TestSuite()
    testSuite.addTest(DocviewDocTestCase("checkInstantion"))
    testSuite.addTest(DocviewDocTestCase("checkModifiable"))
    return testSuite


def main():
    runner = unittest.TextTestRunner()
    runner.run(suite())

if __name__=="__main__":
    main()
    

In this case, DocviewDocTestCase contains two tests: checkInstantion and checkModifiable. This means that two instances of DocviewDocTestCase are added to the testsuite.

I've also added a small test of the universe, to show how to test that your exceptions are fired when you feed your classes illegal input. There are many cases in which you want your code to raise an exception, rather than silently continuing to churn out illegal data. In those cases, you will want the test to succeed when the exception is raised. On the other hand, if the exception is not raised, something happens, and the test fails. That's exactly what the try...except...else block in testUniverse does.

You can thus use the fail() function to let a test noisily fail with a message. There are two similar functions: failIf() and failUnless(), that cause the test to fail if the tested expression is true and if the tested expression is false, respectively:

    def checkFailUnless(self):
        self.failUnless(1==1, "One should be one.")

    def checkFailIf(self):
        self.failIf(1==2,"I don't one to be one, I want it to be two.")
    

A shorter way to check that an exception is indeed raised, is to use assertRaises:

def divide(a, b):
    return a/b
...
def checkShortCircuitException(self):
    self.assertRaises(ZeroDivisionError, divide, 1, 0)
    

The first argument is the exception that should be raised. The second argument of assertRaises() must be a callable object, such as a function. The other arguments are simply the arguments that should be passed to the function.