prev | Draft Version 525 (Thu Dec 1 09:18:50 2005) | next |
unittest
moduleimport unittest
unittest.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.TestCase
class 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())
TestEmpty
testXYZ
method in it, and in CommonTests
CommonTests
:
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 |