Hi
I need some material on Python unit testing framework with examples.
please help me in this regard.

Recommended Answers

All 3 Replies

Here is the example I promised about using doctest for test driven development in python. I will show how you can use it to help you solve a small problem I found in project Euler (http://projecteuler.net/index.php?section=problems&id=158). Here is the problem

Taking three different letters from the 26 letters of the alphabet, character strings of length three can be formed.
Examples are 'abc', 'hat' and 'zyx'.
When we study these three examples we see that for 'abc' two characters come lexicographically after its neighbour to the left.
For 'hat' there is exactly one character that comes lexicographically after its neighbour to the left. For 'zyx' there are zero characters that come lexicographically after its neighbour to the left.
In all there are 10400 strings of length 3 for which exactly one character comes lexicographically after its neighbour to the left.

We now consider strings of n 26 different characters from the alphabet.
For every n, p(n) is the number of strings of length n for which exactly one character comes lexicographically after its neighbour to the left.

What is the maximum value of p(n)?

Ok, to start solving the problem using doctest, I will use 3 files: specif.txt will contain the tests I will use to specify the program, countwords.py will contain the code of the program (the module being tested), and I will also use an executable runspec.py to launch the tests. Each time I type python runspec.py in a console, doctest will execute the tests contained in specif.txt and display the failing tests if any. Here is the content of this launcher file

# runspec.py
from doctest import testfile
testfile("specif.txt")

Now, like in any TDD (test driven development) procedure, let's start by writing a few tests. I put the following in specif.txt , which is a mix of comments/documentation and tests/specifications,

# specif.txt
This is the specification file for the countwords project

The module 'countwords' can be imported
>>> import countwords

Each letter will be identified by a number in [0, 26[. A valid word
has the form
  w = w1 w2 x y w3 w4
where x < y are letters, w1 is an decreasing sequence of letters > y,
w2 and w3 are decreasing sequences of letters in ]x,y[ with no common
element, and w4 is a decreasing sequence of letters < x. if n, n1, n2,
n3, n4 are the lengths of w, w1, w2, w3, w4, then one has
  n = 2 + n1 + n2 + n3 + n4
We wish to count the possible words for a given n. We'll do this by
enumeration. First we generate all possible choices for the pair x, y

>>> from countwords import findpairs
>>> pairs = findpairs()

Let's check the output

>>> isinstance(pairs, list)
True

>>> len(pairs) == 25*26/2
True

All pairs are different
>>> len(set(pairs)) == len(pairs)
True

All pairs satisfy the bounds
>>> filter(lambda (x, y): x < 0 or x >= y or y >= 26, pairs)
[]

Now I can start running python runspec.py . Doctest will complain that there is no module countwords , and, after I create this module, it will complain until the module contains a function findpairs with the desired properties. Here is how to implement one

# countwords.py

def findpairs():
    L = []
    for x in range(26):
        for y in range(x+1, 26):
            L.append((x,y))
    return L

Now doctest is happy, and I realize that I will need some function to compute the binomial coefficients, so I add the following tests to my specification file

#specif.txt
The function 'combi' will return the number of combinations of k
objects among n
>>> from countwords import combi

Let's check it works
>>> [combi(k, 5) for k in range(6)]
[1, 5, 10, 10, 5, 1]

We can add any test we like
>>> combi(4, 10) == (10*9*8*7)/(4*3*2*1)
True

Again, doctest will complain that such a function does not exist, and may be then that it doesn't work as expected, so I add it to my module

# countwords.py

def combi(k, n):
    if k < 0 or k > n:
        raise ValueError, "k must be smaller than n"
    if n-k < k:
        k = n-k
    a, b = 1, 1
    for p in range(1, k+1):
        a *= (n+1-p)
        b *= p
    return a/b

When doctest is satisfied, I add a few more spectifications (tests)

# specif.txt
Now, for a given pair x, y and a given n >= 2, we want to generate all
possible values of (k1, k2, k3, k4). The requirements are that
  0 <= k1, k2, k3, k4
  k1 + k2 + k3 + k4 + 2 = n
  k1 <= 25 - y
  k1 + k2 <= y - x - 1
  k4 <= x
We suppose that countwords contains a generator 'genks' for those k's

>>> from countwords import genks
>>> L = list(genks(4, 10, 4))
>>> print L
[(0, 0, 0, 2), (0, 0, 1, 1), (0, 0, 2, 0), (0, 1, 0, 1), (0, 1, 1, 0), (0, 2, 0, 0), (1, 0, 0, 1), (1, 0, 1, 0), (1, 1, 0, 0), (2, 0, 0, 0)]

We check the conditions

>>> for k1, k2, k3, k4 in genks(4, 10, 6):
...   assert(min(k1, k2, k3, k4) >= 0)
...   assert(k1+k2+k3+k4+2 == 6)
...   assert(k1 <= 25 - 10)
...   assert(k1 + k2 <= 5)
...   assert(k4 <= 4)

The number of admissible words for given x, y, k1, ..., k4 must be

>>> from countwords import countadmissible
>>> x, y, k = 4, 10, (2, 1, 1, 3)
>>> countadmissible(x, y, k) == (
... combi(k[0], 25-y) * combi(k[1], y-x-1)
... * combi(k[2], y-x-1-k[1]) * combi(k[3], x))
True

And I add the corresponding features in countwords.py until all tests pass

def genks(x, y, n):
    n1 = n-2
    z1 = y-x-1
    for k1 in range(1+min(25-y, n1)):
        n2 = n1-k1
        for k2 in range(1+min(n2, z1)):
            n3 = n2-k2
            z2 = z1-k2
            for k3 in range(1+min(n3, z2)):
                if n3-k3 < x:
                    yield (k1, k2, k3, n3-k3)


def countadmissible(x, y, k):
    k1, k2, k3, k4 = k
    return ( combi(k1, 25-y) * combi(k2, y-x-1)
             * combi(k3, y-x-1-k2) * combi(k4, x))

Here is the rest of the specifications and the code (the tests are rather incomplete here, I'm not even sure the results are correct, but you can add tests if you want)

# specif.txt
Now a function to count all words for a given pair x, y and a given n

>>> from countwords import countthem
>>> countthem(4, 10, 6) > 0
True

Now count all words for a given n

>>> from countwords import countall
>>> countall(6) > 0
True

Find the max value
>>> print max([countall(n) for n in range(2, 26)])
213618187786

The program

# countwords.py
def countthem(x, y, n):
    cnt = 0
    for k in genks(x, y, n):
        cnt += countadmissible(x, y, k)
    return cnt

def countall(n):
    cnt = 0
    for x, y in findpairs():
        cnt += countthem(x, y, n)
    return cnt

I hope I convinced you that doctest can really be used for TDD. Note also that existing doctests can be integrated in unittest suite, so there is no loss in using doctest if you want to use unittest later. Hope the post is useful ;)

I also created a small green-yellow-red light widget in wxpython to show if tests failed or not, but that's another story ;).

Hi
Thank you very much,
The article is very good.
Similarly Can anybody share material on nose Unit Testing Framework.
how to write a plugin to nosetests and reading through the libraries of nosetests with some examples.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.