Getting used to writing testing code and running this code in parallel is now considered a good habit. Used wisely, this method helps you define more precisely your code’s intent and have a more decoupled architecture.
Some general rules of testing:
unittest is the batteries-included test module in the Python standard library. Its API will be familiar to anyone who has used any of the JUnit/nUnit/CppUnit series of tools.
Creating test cases is accomplished by subclassing unittest.TestCase.
In [1]:
from unittest import TestCase
def fun(x):
return x + 1
class MyTest(TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_passing_int_value(self):
self.assertEqual(fun(3), 4)
The doctest module searches for pieces of text that look like interactive Python sessions in docstrings, and then executes those sessions to verify that they work exactly as shown.
Doctests have a different use case than proper unit tests: they are usually less detailed and don’t catch special cases or obscure regression bugs. They are useful as an expressive documentation of the main use cases of a module and its components. However, doctests should run automatically each time the full test suite runs.
A simple doctest in a function:
In [3]:
def square(x):
"""Return the square of x.
this should return 4 as 2*2 = 4
>>> square(2)
4
>>> square(-2)
4
This will return 1
>>> square(-1)
2
"""
return x * x
import doctest
doctest.testmod()
Out[3]:
In [ ]:
In [5]:
def listme(x):
"""Return the square of x.
this should return 4 as 2*2 = 4
>>> listme(2)
4
>>> listme(-2)
4
This will return 1
>>> listme(-1)
[-1, -1]
"""
return x, x
import doctest
doctest.testmod()
Out[5]:
When running this module from the command line as in python module.py, the doctests will run and complain if anything is not behaving as described in the docstrings.
In [ ]:
In [6]:
class Room(object):
def __init__(self, name, description):
self.name = name
self.description = description
self.paths = {}
def go(self, direction):
return self.paths.get(direction, None)
def add_paths(self, paths):
self.paths.update(paths)
In [ ]:
In [3]:
from nose.tools import *
def test_room():
gold = Room("GoldRoom",
"""This room has gold in it you can grab. There's a
door to the north.""")
assert_equal(gold.name, "GoldRoom")
assert_equal(gold.paths, {})
def test_room_paths():
center = Room("Center", "Test room in the center.")
north = Room("North", "Test room in the north.")
south = Room("South", "Test room in the south.")
center.add_paths({'north': north, 'south': south})
assert_equal(center.go('north'), north)
assert_equal(center.go('south'), south)
def test_map():
start = Room("Start", "You can go west and down a hole.")
west = Room("Trees", "There are trees here, you can go east.")
down = Room("Dungeon", "It's dark down here, you can go up.")
start.add_paths({'west': west, 'down': down})
west.add_paths({'east': start})
down.add_paths({'up': start})
assert_equal(start.go('west'), west)
assert_equal(start.go('west').go('east'), start)
assert_equal(start.go('down').go('up'), start)
In [3]:
import sys, os
import logging
import unittest
log = logging.getLogger()
from nose import core, loader
#logging.basicConfig(level=logging.DEBUG)
from types import ModuleType
In [4]:
from nose import SkipTest
def test_foo():
assert True
def test_bar():
assert False
def test_baz():
raise SkipTest("Skipped")
import random
import time
def test_generate():
for _ in range(random.randint(0, 10)):
time.sleep(0.25)
yield lambda x: None, _
def fail(x):
time.sleep(0.25)
raise AssertionError("Failed")
for _ in range(random.randint(0, 10)):
yield fail, _
def skip(x):
time.sleep(0.25)
raise SkipTest("Skipped")
for _ in range(random.randint(0, 10)):
yield skip, _
In [ ]: