# HG changeset patch # User Madhusudan.C.S # Date 1283265906 -19800 # Node ID 7455326cac40b4ad44783429228a528f0c1170da # Parent 83b3e357ed08741c3b66ef6dc7a140419a1e5a56 Completed the section on realistic test scenarios and introductory paragraphs on nose. diff -r 83b3e357ed08 -r 7455326cac40 tdd/tdd.rst --- a/tdd/tdd.rst Tue Aug 31 20:14:18 2010 +0530 +++ b/tdd/tdd.rst Tue Aug 31 20:15:06 2010 +0530 @@ -226,41 +226,90 @@ code but also better tests! So let us keep building upon what we have learnt so far. -Let us start writing tests for more realistic test cases. Generally -tests are predetermined as said above, if not the code itself is -flawed. The predetermined tests are stored along with the test code in -some persistent way like in a database, a text file, a file of -specific format like XML or in other way. Let us continue with our -example of GCD function. We will keep all our test cases in a text -file, which is indeed persistent. Let our file have multiple -lines. Each line in this file corresponds to a single test case. Each -line consists of three coloumns: first two coloumns are the integers -for which the GCD has to be computed and the last coloumn is the -expected GCD to the preceding two numbers. So how do we write our -tests to use these test cases? Pretty simple, let us review the -machinery required first. +Let us start writing tests for more realistic test cases. Generally +tests are predetermined as said above, if not the software design in +itself is flawed. The predetermined tests are stored along with the +test code in some persistent format like in a database, a text file, a +file of specific format like XML or in some other way. Let us continue +with our example of GCD function. We will keep all our test cases in a +text file, which is indeed persistent. Let us specify the format of +the test data in our file as follows. + + 1. The file has multiple lines of test data. + 2. Each line in this file corresponds to a single test case. + 3. Each line consists of three comma separated coloumns: - 1. File reading: We already have learnt this in our chapters on + i. First two coloumns are the integers for which the GCD has to + be computed + ii. Third coloumn is the expected GCD to the preceding two + numbers. + +So how do we write our tests to use these test cases? Pretty simple, let +us review the machinery required first. + + 1. File reading: We already have learnt this in the modules on Basic Python. - 2. Parsing read data from file: This just involves a for loop over - the data since we know that file contains lines which are - equivalent to file records and hence parse the data line by line - as strings as we iterate Over it and convert it to required data - type. + 2. Parsing the read data from the file: This just involves a using a + **for** loop which iterates over the data line by line since we + know that the file contains each test case as a sepate line which + are equivalent to the file records and hence parse the data line + by line as strings as we iterate over it and convert it to the + required data type. Since we already have all the machinery required, let us proceed writing -our test cases. +our test cases. We do not need not make any changes to the gcd +function so we will just write down the test here. Let us call our +data file gcd_testcases.dat:: + if __name__ == '__main__': + for line in open('gcd_testcases.dat'): + values = line.split(', ') + a = int(values[0]) + b = int(values[1]) + g = int(values[2]) + tc = gcd(a, b) + if tc != g: + print "Test failed for the case a=%d and b=%d. Expected %d. Obtained %d instead." % (a, b, g, tc) + exit(1) + print "All tests passed!" +When we execute the gcd.py script again we will notice that all the +tests passed. + +Running at the **nose** +======================= -%%%%%%%%% Much Later %%%%%%%%%%%%%%%%% -The idea of placing the tests with in the Python scripts and to -execute them when the script is run as a stand-alone script works well -as long as we have our code in a single Python file or the tests for -each script can be run separately. But in a more realistic software -development scenario, often this is not the case. The code is spread -around multiple Python scripts, each Python script also being called -as a Python module, and across several Python packages. In such a -scenario we may want to do more. +Not too far ahead we go we will start running at the nose saying of +Python developers saying that this is not sufficient to write +complicated tests in an efficient manner and writing tests for the +programs are so important that Python should provide a tool for +managing large tests. To further explain, the idea of placing the +tests with in the Python scripts and to execute them when the script +is run as a stand-alone script works well as long as we have our code +in a single Python file or as long as the tests for each script can be +run separately. But in a more realistic software development scenario, +often this is not the case. The code is spread around multiple Python +scripts, each script also called as a Python module, and also across +several Python packages. + +In such a scenario what we would like to do is to create a separate +directory for holding these test. The structure of this directory is +the exact replica of the Python package hierarchy of our software to +be tested. This structure is especially useful because of the fact +that we have a one to one correspondence to our code and to its test. +Hence it is easy for us to navigate through the tests as we maintain +the existing tests and to add new tests as the code evolves. We have a +collection of tests in the specified structure. Any collection of +tests is called as the test suite for the *software package*. Hence we +shall call this directory of tests as our test suite. + +Fine we have all these, but how do we make our tests aware that they +are the tests for such and such a Python module or code and when +executed must test that corresponding code? To make the lives of +Python developers and testers easy Python provides a very handy tool +called as **nose**. The name should have been pretty evident from the +heading of this section! So in the rest of this module let us discuss +how to use **nose** to write, maintain and extend our tests as the +code evolves.