| prev | Draft Version 525 (Mon Dec 5 17:02:08 2005) | next |
unittest moduleimport unittestunittest.TestCase"test"self)unittest.main()TestCase
"test"TestCase
assert statementsassert_(condition): check that something is true (note the underscore)assertEqual(a, b): check that two things are equalassertNotEqual(a, b): the reverse of the aboveassertRaises(exception, func, …args…): call func with arguments (if provided), and check that it raises the right exceptionfail(): signal an unconditional failure[a, b, c, …] with [a, a+b, a+b+c, …]None?runningSum:
import sys, unittest
def runningSum(seq):
result = seq[0:1]
for i in range(2, len(seq)):
result.append(result[i-1] + seq[i])
return result
class SumTests(unittest.TestCase):
def testEmpty(self):
self.assertEqual(runningSum([]), [])
def testSingle(self):
self.assertEqual(runningSum([3]), [3])
def testDouble(self):
self.assertEqual(runningSum([2, 9]), [2, 11])
def testLong(self):
self.assertEqual(runningSum([-3, 0, 3, -2, 5]), [-3, -3, 0, -2, 3])
if __name__ == '__main__':
unittest.main()
F.E.
======================================================================
ERROR: testLong (__main__.SumTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "running_sum_wrong.py", line 21, in testLong
self.assertEqual(runningSum([-3, 0, 3, -2, 5]), [-3, -3, 0, -2, 3])
File "running_sum_wrong.py", line 6, in runningSum
result.append(result[i-1] + seq[i])
IndexError: list index out of range
======================================================================
FAIL: testDouble (__main__.SumTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "running_sum_wrong.py", line 18, in testDouble
self.assertEqual(runningSum([2, 9]), [2, 11])
File "c:\Python23\lib\unittest.py", line 302, in failUnlessEqual
raise self.failureException, \
AssertionError: [2] != [2, 11]
----------------------------------------------------------------------
Ran 4 tests in 0.000s
FAILED (failures=1, errors=1)
TestCase.assert family of methodsdef runningSum(seq):
result = seq[0:1]
for i in range(1, len(seq)):
result.append(result[i-1] + seq[i])
return result
.... ---------------------------------------------------------------------- Ran 4 tests in 0.000s OK
setUp, the framework will call it before running each testtearDown, it will be run after each testsetUp, and use them in the test methodsclass TestDepends(unittest.TestCase):
def setUp(self):
self.f0 = {}
self.f1 = {'a' : []}
self.f2 = {'a' : ['a']}
self.f3 = {'a' : ['b'], 'b' : []}
self.f4 = {'a' : ['b', 'c'], 'b' : ['a'], 'c' : ['d'], 'd' : []}
def testCanReachSelf(self):
self.assert_(dependsOn(self.f1, 'a', 'a'))
self.assert_(dependsOn(self.f2, 'a', 'a'))
self.assert_(dependsOn(self.f3, 'b', 'b'))
self.assert_(dependsOn(self.f4, 'c', 'c'))
def testSingleStep(self):
self.assert_(dependsOn(self.f3, 'a', 'b'))
self.assert_(dependsOn(self.f4, 'a', 'b'))
self.assert_(dependsOn(self.f4, 'c', 'd'))
def testBackward(self):
self.assert_(dependsOn(self.f4, 'b', 'a'))
def testMultiStep(self):
self.assert_(dependsOn(self.f4, 'a', 'd'))
self.assert_(dependsOn(self.f4, 'b', 'd'))
def testNegative(self):
self.assert_(not dependsOn(self.f1, 'a', 'c'))
self.assert_(not dependsOn(self.f3, 'b', 'a'))
TestCase.assertRaises to check that a specific function raises a specific exceptiontry/except yourselfValueError if the range is empty, or if the set of values is emptyclass TestInRange(unittest.TestCase):
def testNoValues(self):
try:
inRange([], 0.0, 1.0)
except ValueError:
pass
else:
self.fail()
def testBadRange(self):
try:
inRange([0.0], 3.0, 3.0)
inRange([0.0], 4.0, -2.0)
except ValueError:
pass
else:
self.fail()
StringIO and cStringIO modules can read and write strings instead of filesdiff, just a line-by-line comparisonStringIO wrappers around strings)StringIO)class TestDiff(unittest.TestCase):
def wrapAndRun(self, left, right, expected):
left = StringIO(left)
right = StringIO(right)
actual = StringIO()
diff(left, right, actual)
self.assertEqual(actual.getvalue(), expected)
def testEmpty(self):
self.wrapAndRun('', '', '')
def testLengthyMatch(self):
str = 'a\nb\nc\n'
self.wrapAndRun(str, str, '')
def testSingleLineMismatch(self):
self.wrapAndRun('a\n', 'b\n', '1\n')
def testMiddleMismatch(self):
self.wrapAndRun('a\nb\nc\n', 'a\nx\nc\n', '2\n')
Assignment class keep track of who is currently assigned to whatCommonTests to hold shared testsunittest.TestCaseclass CommonTests(object):
'''Tests that can be applied to all fixtures.'''
def testAddNew(self):
'''Check that adding a single new assignment works.'''
priorConsultants = self.fixture.getConsultants()
priorProjects = self.fixture.getProjects()
self.fixture.addAssignment('Alan', 'tables')
self.assertEqual(self.fixture.getByConsultant('Alan'),
Set(['tables']))
self.assertEqual(self.fixture.getByProject('tables'),
Set(['Alan']))
self.assertEqual(self.fixture.getConsultants(),
Set(['Alan']) | priorConsultants)
self.assertEqual(self.fixture.getProjects(),
Set(['tables']) | priorProjects)
CommonTests and unittest.TestCase
class TestEmpty(unittest.TestCase, CommonTests):
'''Test an empty assignment table.'''
def setUp(self):
'''Create the empty assignment table.'''
self.fixture = Assignment()
def testNoConsultants(self):
'''Make sure that nonexistent consultants aren't present.'''
self.assertEqual(self.fixture.getByConsultant('nobody'), Set())
def testNoProjects(self):
'''Make sure that nonexistent projects aren't present.'''
self.assertEqual(self.fixture.getByProject('nothing'), Set())
TestEmptytestXYZ method in it, and in CommonTestsCommonTests:
def testAddDelNew(self):
'''Check that adding and then removing an assignment
leaves things as they were.'''
priorConsultants = self.fixture.getConsultants()
priorProjects = self.fixture.getProjects()
self.fixture.addAssignment('Alan', 'tables')
self.fixture.delAssignment('Alan', 'tables')
self.assertEqual(self.fixture.getConsultants(), priorConsultants)
self.assertEqual(self.fixture.getProjects(), priorProjects)
class TestMulti(unittest.TestCase, CommonTests):
'''Set up common tests with multiple assignments already present.'''
def setUp(self):
self.fixture = Assignment()
self.fixture.addAssignment('Bhargan', 'dishes')
self.fixture.addAssignment('Harald', 'dishes')
self.fixture.addAssignment('Harald', 'floors')
self.fixture.addAssignment('Rachel', 'floors')
self.fixture.addAssignment('Rachel', 'counters')
self.fixture.addAssignment('Sally', 'counters')
Rect) as its first argumentRect) as its second argumentTrue if the rectangles in the list completely cover the first rectangle, or False if they don'tclass TestOverlay(unittest.TestCase):
def testNoRects(self):
self.assert_(not overlay(Rect(0, 0, 1, 1), []))
def testWithSelf(self):
r = Rect(0, 0, 1, 1)
self.assert_(overlay(r, [r]))
def testHalfOnly(self):
self.assert_(not overlay(Rect(0, 0, 2, 2),
[Rect(0, 0, 1, 2)]))
def testTwoHalves(self):
self.assert_(overlay(Rect(0, 0, 2, 2),
[Rect(0, 0, 1, 2), Rect(1, 0, 2, 2)]))
Exercise 13.1:
Python has another unit testing module called doctest.
It searches files for sections of text that look like interactive
Python sessions, then re-executes those sections and checks the
results. A typical use is shown below.
def ave(values):
'''Calculate an average value, or 0.0 if 'values' is empty.
>>> ave([])
0.0
>>> ave([3])
3.0
>>> ave([15, -1.0])
7.0
'''
sum = 0.0
for v in values:
sum += v
return sum / float(max(1, len(values)))
if __name__ == '__main__':
import doctest
doctest.testmod()
Convert a handful of the tests you have written for other
questions in this lecture to use doctest. Do you prefer it
to unittest? Why or why not? Do you think doctest
makes it easier to test small problems? Large ones? Would it be
possible to write something similar for C, Java, Fortran, or
Mathematica?
| prev | Copyright © 2005, Python Software Foundation. See License for details. | next |