from IPython.display import HTML
HTML(open("../include/notes.css", "r").read())
doctest
Module¶Starting with the polar
module from last time.
The idea of doctest
is to insert tests into docstrings, describing what would appear in an interactive Python shell, with ">>>
" denoting inputs, like this:
"""
The PolarPoint Class
>>> print("I am Polar!")
I am Polar!
"""
from math import sin, cos
class PolarPoint:
"""
This class represents a 2D point in polar coordinates defined
by its distance from the center of the reference system and
an angle (in radians) from the positive x-axis.
>>> print("Testing PolarPoint")
Testing PolarPoint
"""
def __init__(self, rho=0.0, theta=0.0):
"""
specifies a polar point by a `rho` (`magnitude`), its
distance from the origin, and `theta` (`argument`) its
polar angle (in radians)
>>> aPoint = PolarPoint(1, 0)
"""
self.rho = rho
self.theta = theta
def rect(self):
"""
returns rectangular (Cartesian) coords of the PolarPoint
as an (x, y) tuple
"""
return (self.rho*cos(self.theta), self.rho*sin(self.theta))
def asComplex(self):
"""
returns the polar point as a complex number
>>> PolarPoint(2, 0).asComplex()
(2+0j)
"""
(real, imag) = self.rect()
return complex(real, imag)
and we use doctest
to run the tests:
!python3 -m doctest demos/0_doctest_polar/0_polar.py
Notice: There's no output. That's because no errors were detected. If you want to see the output, including the tests that passed, pass a "-v
" to the doctest
module:
!python3 -m doctest -v demos/0_doctest_polar/0_polar.py
Trying: print("I am Polar!") Expecting: I am Polar! ok Trying: print('Testing PolarPoint') Expecting: Testing PolarPoint ok Trying: aPolarPoint = PolarPoint(1, 0) Expecting nothing ok Trying: PolarPoint(2, 0).asComplex() Expecting: (2+0j) ok 1 items had no tests: 0_polar.PolarPoint.rect 4 items passed all tests: 1 tests in 0_polar 1 tests in 0_polar.PolarPoint 1 tests in 0_polar.PolarPoint.__init__ 1 tests in 0_polar.PolarPoint.asComplex 4 tests in 5 items. 4 passed and 0 failed. Test passed.
Let's add a few more tests to the module so that every class and method have tests, as well as the module itself, but this time suppose we're not exactly sure what the output is going to be in some cases.
"""
The PolarPoint Class
>>> print("I am Polar!")
I am Polar!
"""
from math import sin, cos
class PolarPoint:
"""
This class represents a 2D point in polar coordinates defined
by its distance from the center of the reference system and
an angle (in radians) from the positive x-axis.
>>> print("Testing PolarPoint")
Testing PolarPoint
"""
def __init__(self, rho=0.0, theta=0.0):
"""
specifies a polar point by a `rho` (`magnitude`), its
distance from the origin, and `theta` (`argument`) its
polar angle (in radians)
>>> PolarPoint()
<__main__.PolarPoint object at 0xb76fceec>
"""
self.rho = rho
self.theta = theta
def rect(self):
"""
returns rectangular (Cartesian) coords of the PolarPoint
as an (x, y) tuple
>>> from math import pi
>>> PolarPoint(2, 0).rect()
(2.0, 0.0)
>>> PolarPoint(2, pi).rect()
(-2.0, 0.0)
"""
return (self.rho*cos(self.theta), self.rho*sin(self.theta))
def asComplex(self):
"""
returns the polar point as a complex number
>>> PolarPoint(2, 0).asComplex()
(2+0j)
"""
(real, imag) = self.rect()
return complex(real, imag)
When we run this, we get:
!python3 -m doctest demos/0_doctest_polar/1_polar_problem.py
********************************************************************** File "demos/0_doctest_polar/1_polar_problem.py", line 25, in 1_polar_problem.PolarPoint.__init__ Failed example: PolarPoint() Expected: <__main__.PolarPoint object at 0xb76fceec> Got: <1_polar_problem.PolarPoint object at 0x7faa4e85cb50> ********************************************************************** File "demos/0_doctest_polar/1_polar_problem.py", line 39, in 1_polar_problem.PolarPoint.rect Failed example: PolarPoint(2, pi).rect() Expected: (-2.0, 0.0) Got: (-2.0, 2.4492935982947064e-16) ********************************************************************** 2 items had failures: 1 of 1 in 1_polar_problem.PolarPoint.__init__ 1 of 3 in 1_polar_problem.PolarPoint.rect ***Test Failed*** 2 failures.
See the problems? doctest
gives us an easy way out: ellipses ("..."), which are like wild card matching. To use them, though, we need to control the doctest
invocation (of doctest.testmod()
). We'll put it in the modular self-test.
"""
The PolarPoint Class
>>> print("I am Polar!")
I am Polar!
"""
from math import sin, cos
class PolarPoint:
"""
This class represents a 2D point in polar coordinates defined
by its distance from the center of the reference system and
an angle (in radians) from the positive x-axis.
>>> print('Testing PolarPoint')
Testing PolarPoint
"""
def __init__(self, rho=0.0, theta=0.0):
"""
specifies a polar point by a `rho` (`magnitude`), its
distance from the origin, and `theta` (`argument`) its
polar angle (in radians)
>>> PolarPoint()
<__main__.PolarPoint object at ...>
"""
self.rho = rho
self.theta = theta
def rect(self):
"""
returns rectangular (Cartesian) coords of the PolarPoint
as an (x, y) tuple
>>> from math import pi
>>> PolarPoint(2, 0).rect()
(2.0, 0.0)
>>> PolarPoint(2, pi).rect()
(-2.0, ...)
"""
return (self.rho*cos(self.theta), self.rho*sin(self.theta))
def asComplex(self):
"""
returns the polar point as a complex number
>>> PolarPoint(2, 0).asComplex()
(2+0j)
"""
(real, imag) = self.rect()
return complex(real, imag)
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
and now the test works:
!python3 demos/0_doctest_polar/2_polar_ellipsis.py -v
Trying: print("I am Polar!") Expecting: I am Polar! ok Trying: print('Testing PolarPoint') Expecting: Testing PolarPoint ok Trying: PolarPoint() Expecting: <__main__.PolarPoint object at ...> ok Trying: PolarPoint(2, 0).asComplex() Expecting: (2+0j) ok Trying: from math import pi Expecting nothing ok Trying: PolarPoint(2, 0).rect() Expecting: (2.0, 0.0) ok Trying: PolarPoint(2, pi).rect() Expecting: (-2.0, ...) ok 5 items passed all tests: 1 tests in __main__ 1 tests in __main__.PolarPoint 1 tests in __main__.PolarPoint.__init__ 1 tests in __main__.PolarPoint.asComplex 3 tests in __main__.PolarPoint.rect 7 tests in 5 items. 7 passed and 0 failed. Test passed.
Let's try a more substantial doctest
example: the rational
module, which implements a Rational
class:
"""
This is the missing docstring.
"""
from math import frexp
class RationalExponentError(Exception):
"""
still missing
"""
pass
def euclid(a, b):
"""
still missing
>>> euclid(9, 21)
3
"""
res = a % b
if res == 0:
return b
else:
return euclid(b, res)
def chrexpo(xArg):
"""
Converts a possibly floating point value to an integer
characteristic and a(n integer) power-of-two exponent and returns
them as a tuple.
"""
(chrst,expo) = frexp(xArg)
while int(chrst) != chrst:
chrst *= 65536
expo -= 16
return (int(chrst), expo)
class Rational:
"""
Allows the performance of rational arithmetic, which is the most
precise form of calculation possible on a digital computer. It
makes heavy use of Python's arbitrary precision 'int's.
from math import pi
print(" Rational(pi):", Rational(pi))
print("Rational(2**0.5):", Rational(2**0.5))
"""
def __init__(self, n, d=1):
"""
>>> Rational(3, 2)
Rational(3, 2)
>>> Rational(5, 17)
Rational(5, 17)
"""
if d == 0:
raise ZeroDivisionError
# If n is, itself rational, do something, well, rational.
# (This also takes care of a Rational d.)
if isinstance(n, Rational):
ratio = n / d
n = ratio.n
d = ratio.d
negn = n < 0
if negn:
n = -n
negd = d < 0
if negd:
d = -d
if negn ^ negd:
nsign = -1
else:
nsign = 1
if int(n) == n:
n = int(n) # force n to be an integer (it might have float type)
else: # i.e. n is not an integer
(chrst, expo) = chrexpo(n)
if expo > 0:
n = chrst * 2**(expo)
else:
n = chrst
d *= 2**(-expo)
if int(d) == d:
d = int(d) # force n to be an integer (it might have float type)
else: # i.e. d is not an integer
(chrst, expo) = chrexpo(d)
if expo > 0:
d = chrst * 2**(expo)
else:
d = chrst
n *= 2**(-expo)
gcd = euclid(n, d)
self.n = nsign * n // gcd
self.d = d // gcd
def __repr__(self):
return 'Rational(' + repr(self.n) + ', ' + repr(self.d) + ')'
def __str__(self):
"""
>>> print(Rational(5, 17))
(5/17)
"""
return '(' + str(self.n) + '/' + str(self.d) + ')'
def __lt__(self, other):
"""
>>> r0 = Rational(3, 2)
>>> r1 = Rational(5, 17)
>>> r0 < r1
False
"""
if isinstance(other, int):
other = Rational(other, 1)
return self.n * other.d < other.n * self.d
def __eq__(self, other):
if isinstance(other, int):
other = Rational(other, 1)
return self.n * other.d == other.n * self.d
def __neg__(self):
return Rational(-self.n, self.d)
def __add__(self, other):
"""
>>> r0 = Rational(3, 2)
>>> r1 = Rational(5, 17)
>>> r0+r1
Rational(61, 34)
>>> r0+1
Rational(5, 2)
"""
if isinstance(other, int):
other = Rational(other, 1)
return Rational(self.n * other.d + other.n * self.d, self.d * other.d)
def __radd__(self, other):
return self.__add__(other)
def __sub__(self, other):
"""
>>> r0 = Rational(3, 2)
>>> r1 = Rational(5, 17)
>>> r0-r1
Rational(41, 34)
"""
if isinstance(other, int):
other = Rational(other, 1)
return Rational(self.n * other.d - other.n * self.d, self.d * other.d)
def __rsub__(self, other):
return -self + other
def __mul__(self, other):
"""
>>> r0 = Rational(3, 2)
>>> r1 = Rational(5, 17)
>>> r0*r1
Rational(15, 34)
>>> r1*3
Rational(15, 17)
"""
if isinstance(other, int):
other = Rational(other, 1)
return Rational(self.n * other.n, self.d * other.d)
def __rmul__(self, other):
return Rational(other * self.n, self.d)
def __truediv__(self, other):
"""
>>> r0 = Rational(3, 2)
>>> r1 = Rational(5, 17)
>>> r0/r1
Rational(51, 10)
"""
if isinstance(other, int):
other = Rational(other, 1)
return Rational(self.n * other.d, self.d * other.n)
def __floordiv__(self, other):
raise ValueError("Floor division not defined for Rationals.")
def __rdiv__(self, other):
return Rational(other * self.d, self.n)
def __pow__(self, expo, base=None):
"""
>>> r0 = Rational(3, 2)
>>> r0**20
Rational(3486784401, 1048576)
"""
if base is not None:
raise ValueError("Can't take the modulus of a Rational")
if isinstance(expo, int):
return Rational(self.n ** expo, self.d ** expo)
elif expo.d == 1:
return Rational(self.n ** expo.n, self.d ** expo.n)
else:
raise RationalExponentError
def positiveRationals():
sum_ = 2
while True:
for i in range(1, sum_):
j = sum_ - i
if euclid(i, j) == 1:
yield Rational(i, j)
sum_ += 1
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS, verbose=True)
!python3 demos/1_doctest_rational/rational.py -v
# reminder: append "-v" to see the successful test results
Trying: r0 = Rational(3, 2) Expecting nothing ok Trying: r1 = Rational(5, 17) Expecting nothing ok Trying: r0+r1 Expecting: Rational(61, 34) ok Trying: r0+1 Expecting: Rational(5, 2) ok Trying: Rational(3, 2) Expecting: Rational(3, 2) ok Trying: Rational(5, 17) Expecting: Rational(5, 17) ok Trying: r0 = Rational(3, 2) Expecting nothing ok Trying: r1 = Rational(5, 17) Expecting nothing ok Trying: r0 < r1 Expecting: False ok Trying: r0 = Rational(3, 2) Expecting nothing ok Trying: r1 = Rational(5, 17) Expecting nothing ok Trying: r0*r1 Expecting: Rational(15, 34) ok Trying: r1*3 Expecting: Rational(15, 17) ok Trying: r0 = Rational(3, 2) Expecting nothing ok Trying: r0**20 Expecting: Rational(3486784401, 1048576) ok Trying: print(Rational(5, 17)) Expecting: (5/17) ok Trying: r0 = Rational(3, 2) Expecting nothing ok Trying: r1 = Rational(5, 17) Expecting nothing ok Trying: r0-r1 Expecting: Rational(41, 34) ok Trying: r0 = Rational(3, 2) Expecting nothing ok Trying: r1 = Rational(5, 17) Expecting nothing ok Trying: r0/r1 Expecting: Rational(51, 10) ok Trying: euclid(9, 21) Expecting: 3 ok 13 items had no tests: __main__ __main__.Rational __main__.Rational.__eq__ __main__.Rational.__floordiv__ __main__.Rational.__neg__ __main__.Rational.__radd__ __main__.Rational.__rdiv__ __main__.Rational.__repr__ __main__.Rational.__rmul__ __main__.Rational.__rsub__ __main__.RationalExponentError __main__.chrexpo __main__.positiveRationals 9 items passed all tests: 4 tests in __main__.Rational.__add__ 2 tests in __main__.Rational.__init__ 3 tests in __main__.Rational.__lt__ 4 tests in __main__.Rational.__mul__ 2 tests in __main__.Rational.__pow__ 1 tests in __main__.Rational.__str__ 3 tests in __main__.Rational.__sub__ 3 tests in __main__.Rational.__truediv__ 1 tests in __main__.euclid 23 tests in 22 items. 23 passed and 0 failed. Test passed.
To show another doctest
feature, let's start with the faro
shuffle program:
"""
This program explores the non-randomness of the traditional 'faro'
method of card shuffling. No matter how many cards there are in a
deck, there is always a finite number of faro shuffles that will
restore their original order. (Of course, a faro shuffle is very hard
to do in practice!)
"""
def faroShuffle(oldDeck):
"""
performs a 'faro' or 'perfect' shuffle
`oldDeck` (a sequence) is the original deck. The shuffled deck is
returned. It does an 'out' shuffle (top and bottom cards
preserved).
"""
# Look how easy Python makes this!
n = len(oldDeck)
newDeck = n*[ 0 ] # initializes result
newDeck[0:n-1:2] = oldDeck[:n//2] # insert left hand
newDeck[1:n:2] = oldDeck[n//2:] # insert right hand
return newDeck
def countShuffles(nCards):
"""
counts the number of faro shuffles required to restore a deck
`nCards` is the number of cards in the deck. It must be an even
positive int.
"""
originalDeck = list(range(nCards))
currentDeck = originalDeck
shuffleCount = 0
while True:
shuffledDeck = faroShuffle(currentDeck)
shuffleCount += 1
if shuffledDeck == originalDeck:
return shuffleCount
currentDeck = shuffledDeck
def main():
nCards = 52
print(('The ordering of a deck of %d cards is'
' restored after %d faro shuffles.'
% (nCards, countShuffles(nCards))))
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
Let's write a test for the faro shuffle. Note that we can include error testing.
"""
This program explores the non-randomness of the traditional 'faro'
method of card shuffling. No matter how many cards there are in a
deck, there is always a finite number of faro shuffles that will
restore their original order. (Of course, a faro shuffle is very hard
to do in practice!)
"""
def faroShuffle(oldDeck):
"""
performs a 'faro' or 'perfect' shuffle
`oldDeck` (a sequence) is the original deck. The shuffled deck is
returned. It does an 'out' shuffle (top and bottom cards
preserved).
>>> # To shuffle two cards...
>>> faroShuffle([0, 1])
[0, 1]
>>> # Four cards...
>>> faroShuffle([0, 1, 2, 3])
[0, 2, 1, 3]
>>> # A deck (range) of 10 cards...
>>> faroShuffle(range(10))
[0, 5, 1, 6, 2, 7, 3, 8, 4, 9]
>>> # Suppose we try to shuffle a list that includes non-integers...
>>> faroShuffle(['queen', 'jack', 'ace', 7])
['queen', 'ace', 'jack', 7]
>>> # Three cards, being an odd number, should raise an exception...
>>> faroShuffle([0, 1, 2])
Traceback (most recent call last):
...
ValueError: attempt to assign sequence of size 2 to extended slice of size 1
>>> # How about something that's not a sequence?
>>> faroShuffle(1)
Traceback (most recent call last):
...
TypeError: object of type 'int' has no len()
>>> # An empty list should be returned unchanged.
>>> faroShuffle([])
[]
>>> # How about an empty argument list?
>>> faroShuffle()
Traceback (most recent call last):
...
TypeError: faroShuffle() missing 1 required positional argument: 'oldDeck'
"""
# Look how easy Python makes this!
n = len(oldDeck)
newDeck = n*[ 0 ] # initializes result
newDeck[0:n-1:2] = oldDeck[:n//2] # insert left hand
newDeck[1:n:2] = oldDeck[n//2:] # insert right hand
return newDeck
def countShuffles(nCards):
"""
counts the number of faro shuffles required to restore a deck
`nCards` is the number of cards in the deck. It must be an even
positive int.
>>> countShuffles(52)
8
"""
originalDeck = list(range(nCards))
currentDeck = originalDeck
shuffleCount = 0
while True:
shuffledDeck = faroShuffle(currentDeck)
shuffleCount += 1
if shuffledDeck == originalDeck:
return shuffleCount
currentDeck = shuffledDeck
def main():
nCards = 52
print(('The ordering of a deck of %d cards is'
' restored after %d faro shuffles.'
% (nCards, countShuffles(nCards))))
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
The doctest for faroShuffle()
is thorough, but really long. It clutters up the function. Here's how we make it external. First, move the test "dialog" to a separate file, say faro_shuffle_test.txt
:
The source file then gets much more readable:
"""
This program explores the non-randomness of the traditional 'faro'
method of card shuffling. No matter how many cards there are in a
deck, there is always a finite number of faro shuffles that will
restore their original order. (Of course, a faro shuffle is very hard
to do in practice!)
"""
def faroShuffle(oldDeck):
"""
performs a 'faro' or 'perfect' shuffle
`oldDeck` (a sequence) is the original deck. The shuffled deck is
returned. It does an 'out' shuffle (top and bottom cards
preserved).
"""
# Look how easy Python makes this!
n = len(oldDeck)
newDeck = n*[ 0 ] # initializes result
newDeck[0:n-1:2] = oldDeck[:n//2] # insert left hand
newDeck[1:n:2] = oldDeck[n//2:] # insert right hand
return newDeck
def countShuffles(nCards):
"""
counts the number of faro shuffles required to restore a deck
`nCards` is the number of cards in the deck. It must be an even
positive int.
"""
originalDeck = list(range(nCards))
currentDeck = originalDeck
shuffleCount = 0
while True:
shuffledDeck = faroShuffle(currentDeck)
shuffleCount += 1
if shuffledDeck == originalDeck:
return shuffleCount
currentDeck = shuffledDeck
def main():
nCards = 52
print(('The ordering of a deck of %d cards is'
' restored after %d faro shuffles.'
% (nCards, countShuffles(nCards))))
if __name__ == '__main__':
import doctest
doctest.testfile('faro_shuffle_test.txt', module_relative=False, verbose=True)
Trying: from faro_doctest import faroShuffle Expecting nothing ok Trying: faroShuffle([0, 1]) Expecting: [0, 1] ok Trying: faroShuffle([0, 1, 2, 3]) Expecting: [0, 2, 1, 3] ok Trying: faroShuffle(range(10)) Expecting: [0, 5, 1, 6, 2, 7, 3, 8, 4, 9] ok Trying: faroShuffle(['queen', 'jack', 'ace', 7]) Expecting: ['queen', 'ace', 'jack', 7] ok Trying: faroShuffle([0, 1, 2]) Expecting: Traceback (most recent call last): ... ValueError: attempt to assign sequence of size 2 to extended slice of size 1 ok Trying: faroShuffle(1) Expecting: Traceback (most recent call last): ... TypeError: object of type 'int' has no len() ok Trying: faroShuffle([]) Expecting: [] ok Trying: faroShuffle() Expecting: Traceback (most recent call last): ... TypeError: faroShuffle() missing 1 required positional argument: 'oldDeck' ok 1 items passed all tests: 9 tests in faro_shuffle_test.txt 9 tests in 1 items. 9 passed and 0 failed. Test passed.
unittest
Module¶When testing on a larger scale with explicit test code, possibly in files distinct from the module source, there's the unittest
module. Here's a simple, self-contained example:
import unittest
def list_sort_test():
list1 = [1, 5, 3, 2, 4]
sorted_list = [1, 2, 3, 4, 5]
list1.sort()
assert sorted_list == list1
test_list_sort = unittest.FunctionTestCase(list_sort_test)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(test_list_sort)
unittest.case.FunctionTestCase (list_sort_test) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.002s OK
<unittest.runner.TextTestResult run=1 errors=0 failures=0>
Unit test is all about building test cases.
unittest.TestCase
Class¶Let's apply this to faro
. Here's a unittest
for faro
. Notice how we create two test cases as child classes of unittest.TestCase
, one for each function in faro
.
Note that the methods of the class begin with "test_
". This allows us to use unittest.TestCase
as a mixin to build testing directly into existing classes. (We don't do that here.)
"""
This module tests the functions in the "faro" module using the
"unittest" module.
"""
import unittest
from faro import faroShuffle, countShuffles
class TestFaroShuffle(unittest.TestCase):
def test_twoCards(self):
"""
two card shuffle test
"""
self.assertEqual(faroShuffle([0, 1]), [0, 1])
def test_fourCards(self):
self.assertEqual(faroShuffle([0, 1, 2, 3]), [0, 2, 1, 3])
def test_tenCards(self):
self.assertEqual(faroShuffle(range(10)),
[0, 5, 1, 6, 2, 7, 3, 8, 4, 9])
def test_shuffleAnything(self):
self.assertEqual(faroShuffle(['queen', 'jack', 'ace', 7]),
['queen', 'ace', 'jack', 7])
def test_threeCards(self):
self.assertRaises(ValueError, faroShuffle, [0, 1, 2])
def test_nonsequence(self):
self.assertRaises(TypeError, faroShuffle, 1)
def test_emptyList(self):
self.assertEqual(faroShuffle([]), [])
def test_noArgument(self):
self.assertRaises(TypeError, faroShuffle)
class TestCountShuffles(unittest.TestCase):
def test_twoCards(self):
self.assertEqual(countShuffles(2), 1)
def test_fiftyTwoCards(self):
self.assertEqual(countShuffles(52), 8)
def test_oneThousandCards(self):
self.assertEqual(countShuffles(1024), 10)
if __name__ == '__main__':
unittest.main()
E ====================================================================== ERROR: /home/bobl/ (unittest.loader._FailedTest) ---------------------------------------------------------------------- AttributeError: module '__main__' has no attribute '/home/bobl/' ---------------------------------------------------------------------- Ran 1 test in 0.001s FAILED (errors=1)
An exception has occurred, use %tb to see the full traceback. SystemExit: True
/usr/local/lib/python3.8/dist-packages/IPython/core/interactiveshell.py:3425: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
We need to run this from the shell:
!python3 faro_unittest.py -v
test_fiftyTwoCards (__main__.TestCountShuffles) ... ok test_oneThousandCards (__main__.TestCountShuffles) ... ok test_twoCards (__main__.TestCountShuffles) ... ok test_emptyList (__main__.TestFaroShuffle) ... ok test_fourCards (__main__.TestFaroShuffle) ... ok test_noArgument (__main__.TestFaroShuffle) ... ok test_nonsequence (__main__.TestFaroShuffle) ... ok test_shuffleAnything (__main__.TestFaroShuffle) ... ok test_tenCards (__main__.TestFaroShuffle) ... ok test_threeCards (__main__.TestFaroShuffle) ... ok test_twoCards (__main__.TestFaroShuffle) two card shuffle test ... ok ---------------------------------------------------------------------- Ran 11 tests in 0.001s OK
unittest.FunctionTestCase
Class¶This class can wrap a single test function and turn it into a test case.
"""
This module shows how to create a TestCase from a single function.
"""
import unittest
from faro import faroShuffle
def faroShuffleTest():
lst = [1, 2, 3, 4, 5, 6]
good = [1, 4, 2, 5, 3, 6]
new = faroShuffle(lst)
assert new == good
test_faroShuffle = unittest.FunctionTestCase(faroShuffleTest)
if __name__ == '__main__':
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(test_faroShuffle)
unittest.case.FunctionTestCase (faroShuffleTest) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.002s OK
unittest.TestSuite
Class¶In a large testing system, it's useful to organize individual tests into "suites" that can be organized by functionality, cost of testing, responsible group, result verbosity, etc. The same test can be included in several groups.
"""
This module shows how to create a TestSuite that includes two TestCases.
"""
import unittest
import faro_unittest
testSuite = unittest.TestSuite()
testSuite.addTest(faro_unittest.TestFaroShuffle("run"))
testSuite.addTest(faro_unittest.TestCountShuffles("run"))
print("running the TestSuite with a default TextTestRunner...")
testTextRunnerDefault = unittest.TextTestRunner()
testTextRunnerDefault.run(testSuite)
print(70*'=')
if 0: # should work in principle, but raises a TypeError for some reason
print("running the same TestSuite with a verbose TextTestRunner...")
testTextRunnerVerbose = unittest.TextTestRunner(verbosity=2)
testTextRunnerVerbose.run(testSuite)
..
running the TestSuite with a default TextTestRunner... ======================================================================
---------------------------------------------------------------------- Ran 2 tests in 0.117s OK
doctest
Tests in the unittest
Framework¶It's possble to incorporate doctest
tests in the unittest
framework. See the book for details.