Next page : Pyunit and Eclipse

PyUnit-guide

PyUnit is a framework designed for repetitive testing of programs. Support for PyUnit can be found in most major APIs such as Eclipse etc.

The Goblin system uses PyUnit to test the students code with instructor-defined tests It is also very useful if you can run these tests on your own machine to confrm that they work before you send your solution to be checked by Goblin.

The structure of a PyUnit test class (Python version 2.6)

For the compiler to be able to do the tests, we must import the corresponding module unittest to the namespace. So lets add the following line:

import unittest

The test class must inherit the unittest.TestCase class.

The class inside the test module shold be named Test. This is a requirement of Goblin-tests, not of PyUnit.

End the test file with the rows:

if __name__ == "__main__":
    unittest.main()

Test methods

Each PyUnit test class holds a number of separate tests which can test different aspects of the implemented code. These tests are written into separate methods which are named starting with test.

The idea of a unit test is to compare data retrieved somehow from the program to an expected set of data. The comparison is done using the assertXXX methods in the TestCase class. The most commonly used assertXXX methods are listed below. The assert method typically gets as a parameter a message to display if the inspected value differs from the expected one. The two(or one) other values are the expected value and the actual value. One test method can have as many assert-calls as is considered necessary.

  • assertEqual(first, second, msg=None)
  • assertTrue(expr, msg=None)
  • assertFalse(expr, msg=None)

What do asserts do?

If an assert method is called inside a test method and the result is not satisfactory, PyUnit does not continue runnig the test but marks it as failed. IDEs like Eclipse typically show also the message in the assert.

Beginning and ending tasks

In some cases you want all tests to have the same basic initial setup. This can be accomplished with PyUnit by naming the initialization method as setUp. Correspondingly each test can be followed by an automated cleanup etc. by naming such a method as tearDown.

Example

This is the class we are going to test.

class Hello(object):

    def get_message(self):

        return "Hello World"


    def anna_viesti(self):

        return "Hei Maailma!"

The program specification we read when implementing the tests states that the english method should return the String "Hello World!" and it's finnish counterpart "Hei Maailma!". We can now proceed to write the test class:

import unittest

from hello_world import Hello

class Test(unittest.TestCase):


    # Creates the Hello-object being tested. 
    # You could do this in the test-methods as well.



    def setUp(self):

        self.hello = Hello()


    # Tests the english method for the string "Hello World!".

    def test_english(self):

        output = self.hello.get_message()

        self.assertEqual(output,
                      "Hello World!",
                      "get_message() does not output the correct value.")


    # Tests the finnish method for the string "Hei Maailma!".

    def test_finnish(self):

        output = self.hello.anna_viesti()

        self.assertEqual(output,
                         "Hei Maailma!",
                         "hae_viesti() does not output the correct value.")

if __name__ == "__main__":
    unittest.main()

If we take the classes above and try them out in e.g. Eclipse we should note that the test for the english method does not pass because the exclamation point in the end of the string is missing. We can now correct this bug in our code and rerun the test, which hopefully should now pass. It might however be that the fix creates a problem somewhere else, failing another testcase - It could be for example, that the bug was compensated somewhere else in the code by adding the exclamation point - This would now result in two exclamation points. If the test set covers the funtionality well enough we should be able to spot this bug as well during the next run of the PyUnit tests.

The example above is not too interesting as the strings were not created by code but were used as contants. Typically test cases are like pop quizzes in school. A teacher cannot tell if students know how to conjugate Finnish words. The only way to know would be to ask about the grammar used. Instead the teacher (coder) can easily come up with a few words and the corresponding conjugations which test the knowledge of different conjugation rules.

The unit test can therefore be seen as a pop quiz for the program - a selected set of tasks with known expected results are given to test the program.

PyUnit in Eclipse

All the newer Eclipse IDEs have integrated PyUnit-functionality, which help when tests are written and run. On the next page you can see our example tested inside Eclipse.

Next page : PyUnit and Eclipse

If you haven't used eclipse before and want to start now, then please go to eclipse.org

PyUnit in unix/dos environment

The test module can be run like any other Python module:

login:> python test.py
test_english (__main__.Test) ... FAIL
test_finnish (__main__.Test) ... ok

======================================================================
FAIL: test_english (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 26, in test_english
    "get_message() does not output the correct value.")
AssertionError: get_message() does not output the correct value.

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)